Undantag är en grundläggande del av programmering i Ruby, vilket gör det möjligt för utvecklare att hantera fel på ett elegant sätt och säkerställa robusta, feltoleranta applikationer. Rubys undantagshanteringsmekanism är intuitiv men ändå kraftfull, vilket gör det möjligt för utvecklare att skapa fel när något går fel och rädda dem för att förhindra programkrascher. I den här guiden på 2000 ord utforskar vi hur man skapar och räddar undantag i Ruby, och täcker grunderna, avancerade tekniker, bästa praxis och verkliga exempel.
Vad är undantag i Ruby?
Undantag i Ruby är objekt som representerar fel eller oväntade förhållanden under programkörning. När ett fel uppstår - till exempel ett försök att dividera med noll, åtkomst till en icke-existerande fil eller ett nätverksfel - skapar Ruby ett undantag. Om det inte hanteras leder undantaget till att programmet avslutas med ett felmeddelande.
Rubys undantagssystem är uppbyggt kring Undantag klassen, som fungerar som roten i undantagshierarkin. Underklasser som Standardfel, Runtidsfel, Argumentfel, och IngenMetodFel hantera specifika typer av fel. Utvecklare kan också definiera egna undantagsklasser för att representera applikationsspecifika fel.
Undantagshantering i Ruby kretsar kring två nyckelåtgärder:
- Höjning: Utlösning av ett undantag när ett fel inträffar.
- Räddning: Fånga upp och hantera undantag för att förhindra programkrascher.
Nu ska vi titta närmare på hur man effektivt höjer och räddar undantag.
Undantag i Ruby
Ett undantag är en process som signalerar att ett fel eller ett oväntat tillstånd har inträffat. Ruby tillhandahåller höja metod (och dess alias misslyckas) för att utlösa undantag.
Den höja Metod
Det enklaste sättet att skapa ett undantag är att använda höja metod utan argument, vilket ger upphov till en RuntimeFel (en underklass till Standardfel):
rubin höja # => RuntimeError: ohanterat undantag
Du kan också ange ett felmeddelande:
ruby raise "Något gick fel!" # => RuntimeError: Något gick fel!
Om du vill ta upp en specifik undantagsklass skickar du klassen som första argument och meddelandet som andra:
ruby raise ArgumentError, "Invalid input provided" # => ArgumentError: Ogiltig inmatning tillhandahållen
Anpassade undantagsklasser
För mer komplexa applikationer kanske du vill definiera egna undantagsklasser för att representera specifika fel. Anpassade undantag ärver från Standardfel eller en av dess underklasser för att säkerställa kompatibilitet med Rubys standardräddningsbeteende.
Exempel:
ruby class AuthenticationError AuthenticationError: Ogiltiga autentiseringsuppgifter
Genom att definiera Autentiseringsfelkan du hantera autentiseringsrelaterade fel separat från generiska fel.
Undantag med motivering
Med Ruby kan du koppla en "orsak" till ett undantag, vilket är användbart för felsökning. Orsaken är det ursprungliga undantaget som ledde till det aktuella undantaget. Använd undantag metod för att komma åt den:
ruby börja raise "Ursprungligt fel" räddning => e raise "Nytt fel" # Det ursprungliga felet bevaras som orsak avsluta
Du kan inspektera orsaken med e.orsak:
ruby
börja
börja
raise "Ursprungligt fel"
räddning => e
höja "Nytt fel"
slut
räddning => e
puts e.message # => Nytt fel
puts e.cause.message # => Ursprungligt fel
slutRäddning av undantag
Genom att rädda undantag kan du fånga upp och hantera fel på ett elegant sätt och förhindra att ditt program kraschar. Ruby använder påbörja/räddning block för att hantera undantag.
Den Börja/räddning Block
Den grundläggande strukturen i en påbörja/räddning block är:
ruby börja # Kod som kan ge upphov till ett undantag Rädda # Hantera undantaget avsluta
Exempel:
ruby börja resultat = 10 / 0 räddning puts "Ett fel inträffade!" slut # Utgång: Ett fel inträffade!
Som standard, räddning fångar Standardfel och dess underklasser. Om du inte anger någon undantagsklass är det likvärdigt med räddning StandardError.
Hantering av specifika undantag
Om du vill hantera specifika undantag anger du undantagsklassen i räddning klausul:
ruby börja resultat = 10 / 0 räddar ZeroDivisionError puts "Kan inte dividera med noll!" räddning ArgumentFel puts "Ogiltigt argument angavs!" slut # Utmatning: Kan inte dividera med noll!
Du kan också fånga upp undantagsobjektet för vidare granskning:
ruby
börja
raise ArgumentError, "Ogiltig inmatning"
rescue ArgumentError => e
puts "Fel: #{e.message}"
slut
# Utmatning: Fel: Ogiltig inmatningAnvänder sig av annan och säkerställa
Ruby innehåller två ytterligare klausuler för undantagshantering:
annan: Utförs om inget undantag har uppstått.säkerställa: Exekveras oavsett om ett undantag inträffar, användbart för rensningsuppgifter.
Exempel:
ruby
börja
puts "Utför operation ..."
resultat = 10 / 2
räddar ZeroDivisionError
puts "Kan inte dividera med noll!"
else
puts "Operationen lyckades: #{resultat}"
säkerställa
puts "Städa upp ..."
slut
# Utgång:
# Utför operation...
# Operationen lyckades: 5
# Städa upp...Om ett undantag inträffar:
ruby
börja
puts "Utför operation ..."
resultat = 10 / 0
räddar ZeroDivisionError
puts "Kan inte dividera med noll!"
else
puts "Operationen lyckades: #{resultat}"
säkerställa
puts "Städa upp ..."
slut
# Utgång:
# Utför operation...
# Kan inte dividera med noll!
# Städar upp...Den Försök igen Sökord
Den Försök igen nyckelordet kan du försöka igen med Börja blockera efter att ett undantag har fångats. Detta är användbart för scenarier som att försöka på nytt med misslyckade nätverksförfrågningar.
Exempel:
ruby
försök = 0
börja
försök += 1
puts "Försök #{försök}"
raise "Anslutningen misslyckades"
räddning
Försök igen om försök < 3
puts "Ger upp efter #{försök} försök"
slut
# Utmatning:
# Försök 1
# Försök 2
# Försök 3
# Ger upp efter 3 försökAnvänd retry försiktigt för att undvika oändliga loopar.
Bästa praxis för undantagshantering
- Särskilda undantag för räddningstjänst: Undvik nakna
räddningklausuler, eftersom de fångar allaStandardfelunderklasser och kan dölja oväntade fel. Specificera exakt vilka undantag du förväntar dig.rubin # Bad börja # Kod räddning # Fångar upp allt slut # Bra börja # Kod rescue ArgumentFel, TypFel # Hantera specifika fel avsluta
- Håll räddningsblocken små: Packa bara in den kod som kan ge upphov till ett undantag. Detta förbättrar läsbarheten och förhindrar att orelaterade fel fångas upp.
- Tillhandahålla meningsfulla felmeddelanden: När du gör undantag, inkludera tydliga, handlingsbara meddelanden för att underlätta felsökning.
- Använda anpassade undantag för domänlogik: Skapa egna undantagsklasser för applikationsspecifika fel för att göra din kod mer uttrycksfull och underhållbar.
- Undvik att överanvända undantag för flödeskontroll: Undantag är till för exceptionella fall, inte för att styra programflödet. Använd conditionals för förväntade scenarier.
rubin # Bad börja värde = hash[:nyckel] räddning värde = nil slut # Bra värde = hash[:nyckel] || nil
- Städa upp resurser med
säkerställa: Användningsäkerställaför att stänga filer, databasanslutningar eller andra resurser, även om ett undantag inträffar.
Exempel från den verkliga världen
Filhantering
Läsning av en fil kan ge upphov till undantag som Errno::ENOENT (filen hittades inte) eller Errno::EACCES (tillstånd nekat). Så här hanterar du dem:
ruby
börja
File.open("nonexistent.txt", "r") do |file|
sätter fil.läs
slut
räddning Errno::ENOENT
puts "Filen hittades inte!"
räddning Errno::EACCES
puts "Tillstånd nekat!"
säkerställa
puts "Filoperationen slutförd."
slut
# Utmatning: Filen hittades inte!
# Filoperationen slutförd.API-anrop
När du gör HTTP-förfrågningar kan det hända att du stöter på nätverksfel eller ogiltiga svar. Med hjälp av httparty gem:
ruby
kräver 'httparty'
börja
svar = HTTParty.get('https://api.example.com/data')
räddning HTTParty::Fel => e
puts "API-begäran misslyckades: #{e.message}"
räddning SocketError
puts "Nätverksfel: Kunde inte ansluta till servern"
annat
puts "Mottaget svar: #{response.body}"
slutAnpassad undantagshantering i en klass
Här är ett exempel på en klass som hanterar betalningar och använder anpassade undantag:
ruby
class PaymentError < Standardfel; end
class InsufficientFundsError < Betalningsfel; end
class InvalidCardError card.balance
card.balance -= belopp
puts "Betalning på #{belopp} behandlad framgångsrikt"
slut
privat
def giltigt_kort?(kort)
kort.nummer.längd == 16
slut
slut
klass Kort
attr_accessor :nummer, :balans
def initialize(nummer, saldo)
@number = antal
@balans = balans
slut
slut
kort = Card.new("1234567890123456", 50)
processor = PaymentProcessor.new
börja
processor.process_payment(100, kort)
rescue InsufficientFundsError => e
puts "Fel: #{e.message}"
rescue InvalidCardError => e
puts "Fel: #{e.message}"
slut
# Utmatning: Fel: Inte tillräckligt med medelAvancerad undantagshantering
Nested Rescues
Du kan bygga bo påbörja/räddning block för att hantera undantag på olika nivåer:
ruby
börja
börja
raise "Inre fel"
räddning
puts "Fångade upp inre fel"
höja "Yttre fel"
slut
Räddning
puts "Fångade yttre fel"
slut
# Utmatning:
# Fångade inre fel
# Fångade yttre felUndantagshierarki
Att förstå Rubys undantagshierarki är avgörande. Viktiga klasser inkluderar:
UndantagM: Rotklass för alla undantag.Standardfel: Standard förräddningutan klass; de flesta inbyggda undantag ärver från den.RuntimeFel: Standard förhöjautan en klass.NoMethodError, ArgumentError, TypeErroretc.: Specifika feltyper.
För att fånga upp alla undantag (inklusive ickeStandardfel sådana som Systemavslut), använd rescue Exception:
ruby börja avsluta räddning Exception puts "Fångad utgång" slut # Utgång: Fångad utgång
Använder sig av räddning_från i Rails
I Ruby on Rails kan du använda räddning_från i styrenheter för att hantera undantag globalt:
ruby
klass ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, med: :not_found
privat
def not_found
renderar fil: 'public/404.html', status: :not_found
slut
slutDetta tillvägagångssätt centraliserar undantagshanteringen för specifika styrenheter.
Vanliga fallgropar att undvika
- Fånga alla undantag blint: Använda
räddningutan att ange en undantagsklass kan dölja buggar. - Överanvändning
Försök igen: Att försöka igen på obestämd tid kan leda till oändliga loopar eller dölja underliggande problem. - Ignorera detaljer om undantag: Inspektera alltid undantagsobjektet (
e.meddelande, e.bakspårning) för felsökning. - Uppmärksamma fel som inte är standardfel: Undvik att skapa undantag som inte ärver från
Standardfel, eftersom de inte kommer att fångas upp som standardräddningklausuler. - Städa inte upp resurser: Glömmer att använda
säkerställakan lämna filer eller anslutningar öppna.
Slutsats
Att lyfta fram och rädda undantag i Ruby är ett kraftfullt sätt att hantera fel och bygga robusta applikationer. På RailsCarmaett ledande Ruby on Rails utvecklingsföretaganvänder vi dessa tekniker för att skapa tillförlitliga och underhållbara lösningar. Genom att använda höja för att signalera fel, räddning för att fånga dem, och verktyg som försök igen, annars, och säkerställakan utvecklare hantera fel på ett effektivt sätt. Anpassade undantagsklasser och specifika räddningsklausuler gör din kod tydligare och mer precis. Genom att följa bästa praxis, till exempel att rädda specifika undantag, hålla räddningsblocken små och använda meningsfulla felmeddelanden, får du underhållbar och tillförlitlig kod.
Oavsett om du hanterar filoperationer, API-anrop eller domänspecifik logik, ger Rubys undantagshanteringssystem flexibiliteten att hantera fel på ett elegant sätt. Genom att behärska dessa tekniker och undvika vanliga fallgropar hjälper RailsCarma företag att bygga motståndskraftiga Ruby-applikationer som hanterar fel med förtroende.