Ruby - Ausnahmen
Die Ausführung und die Ausnahme gehören immer zusammen. Wenn Sie eine Datei öffnen, die nicht vorhanden ist, und wenn Sie diese Situation nicht richtig behandelt haben, wird Ihr Programm als von schlechter Qualität angesehen.
Das Programm stoppt, wenn eine Ausnahme auftritt. Daher werden Ausnahmen verwendet, um verschiedene Arten von Fehlern zu behandeln, die während einer Programmausführung auftreten können, und um geeignete Maßnahmen zu ergreifen, anstatt das Programm vollständig anzuhalten.
Ruby bietet einen guten Mechanismus, um Ausnahmen zu behandeln. Wir fügen den Code, der eine Ausnahme auslösen könnte, in einen Anfangs- / Endblock ein und verwenden Rettungsklauseln , um Ruby die Arten von Ausnahmen mitzuteilen, die wir behandeln möchten.
Syntax
begin
# -
rescue OneTypeOfException
# -
rescue AnotherTypeOfException
# -
else
# Other exceptions
ensure
# Always will be executed
end
Alles von Anfang bis zur Rettung ist geschützt. Wenn während der Ausführung dieses Codeblocks eine Ausnahme auftritt, wird die Steuerung zwischen Rettung und Ende an den Block übergeben .
Für jede Rettungsklausel im beginnen Block vergleicht Ruby den erhöhten Ausnahme gegen jeden der Parameter der Reihe nach . Die Übereinstimmung ist erfolgreich, wenn die in der Rettungsklausel genannte Ausnahme dem Typ der aktuell ausgelösten Ausnahme entspricht oder eine Oberklasse dieser Ausnahme ist.
Für den Fall, dass eine Ausnahme keinem der angegebenen Fehlertypen entspricht, dürfen wir nach allen Rettungsklauseln eine else- Klausel verwenden .
Beispiel
#!/usr/bin/ruby
begin
file = open("/unexistant_file")
if file
puts "File opened successfully"
end
rescue
file = STDIN
end
print file, "==", STDIN, "\n"
Dies führt zu folgendem Ergebnis. Sie können sehen, dass STDIN die Datei ersetzt, weil das Öffnen fehlgeschlagen ist.
#<IO:0xb7d16f84>==#<IO:0xb7d16f84>
Retry-Anweisung verwenden
Sie können eine Ausnahme mit erfassen Rettungsblock und dann Verwendung Retry - Anweisung auszuführen , beginnen Block von Anfang an .
Syntax
begin
# Exceptions raised by this code will
# be caught by the following rescue clause
rescue
# This block will capture all types of exceptions
retry # This will move control to the beginning of begin
end
Beispiel
#!/usr/bin/ruby
begin
file = open("/unexistant_file")
if file
puts "File opened successfully"
end
rescue
fname = "existant_file"
retry
end
Das Folgende ist der Ablauf des Prozesses -
- Beim Öffnen ist eine Ausnahme aufgetreten.
- Ging zu retten. fname wurde neu zugewiesen.
- Durch einen erneuten Versuch ging es an den Anfang des Anfangs.
- Diese Zeitdatei wird erfolgreich geöffnet.
- Fortsetzung des wesentlichen Prozesses.
NOTE- Beachten Sie, dass dieser Beispielcode unendlich oft wiederholt wird, wenn die Datei mit dem neu ersetzten Namen nicht vorhanden ist. Seien Sie vorsichtig , wenn Sie verwenden Wiederholungs für einen Ausnahmeprozess.
Raise-Anweisung verwenden
Sie können die Anweisung raise verwenden , um eine Ausnahme auszulösen. Die folgende Methode löst bei jedem Aufruf eine Ausnahme aus. Die zweite Nachricht wird gedruckt.
Syntax
raise
OR
raise "Error Message"
OR
raise ExceptionType, "Error Message"
OR
raise ExceptionType, "Error Message" condition
Das erste Formular löst einfach die aktuelle Ausnahme erneut aus (oder einen RuntimeError, wenn keine aktuelle Ausnahme vorliegt). Dies wird in Ausnahmebehandlungsroutinen verwendet, die eine Ausnahme abfangen müssen, bevor sie weitergeleitet werden.
Das zweite Formular erstellt eine neue RuntimeError- Ausnahme und setzt die Nachricht auf die angegebene Zeichenfolge. Diese Ausnahme wird dann im Aufrufstapel ausgelöst.
Das dritte Formular verwendet das erste Argument, um eine Ausnahme zu erstellen, und setzt dann die zugehörige Nachricht auf das zweite Argument.
Das vierte Formular ähnelt dem dritten Formular, Sie können jedoch eine beliebige bedingte Anweisung hinzufügen, es sei denn , Sie möchten eine Ausnahme auslösen.
Beispiel
#!/usr/bin/ruby
begin
puts 'I am before the raise.'
raise 'An error has occurred.'
puts 'I am after the raise.'
rescue
puts 'I am rescued.'
end
puts 'I am after the begin block.'
Dies führt zu folgendem Ergebnis:
I am before the raise.
I am rescued.
I am after the begin block.
Ein weiteres Beispiel für die Verwendung von Raise -
#!/usr/bin/ruby
begin
raise 'A test exception.'
rescue Exception => e
puts e.message
puts e.backtrace.inspect
end
Dies führt zu folgendem Ergebnis:
A test exception.
["main.rb:4"]
Verwenden Sie sure-Anweisung
Manchmal müssen Sie sicherstellen, dass am Ende eines Codeblocks eine gewisse Verarbeitung erfolgt, unabhängig davon, ob eine Ausnahme ausgelöst wurde. Beispielsweise kann beim Eintritt in den Block eine Datei geöffnet sein, und Sie müssen sicherstellen, dass sie beim Beenden des Blocks geschlossen wird.
Die Sicherungsklausel macht genau das. Stellen Sie sicher, dass die letzte Rettungsklausel verwendet wird und einen Codeabschnitt enthält, der immer ausgeführt wird, wenn der Block beendet wird. Es spielt keine Rolle, ob der Block normal beendet wird, ob er eine Ausnahme auslöst und rettet oder ob er durch eine nicht erfasste Ausnahme beendet wird, der Sicherstellungsblock wird ausgeführt.
Syntax
begin
#.. process
#..raise exception
rescue
#.. handle error
ensure
#.. finally ensure execution
#.. This will always execute.
end
Beispiel
begin
raise 'A test exception.'
rescue Exception => e
puts e.message
puts e.backtrace.inspect
ensure
puts "Ensuring execution"
end
Dies führt zu folgendem Ergebnis:
A test exception.
["main.rb:4"]
Ensuring execution
Verwenden der else-Anweisung
Wenn die else- Klausel vorhanden ist, folgt sie den Rettungsklauseln und bevor sie sichergestellt wird .
Der Hauptteil einer else- Klausel wird nur ausgeführt, wenn vom Hauptteil des Codes keine Ausnahmen ausgelöst werden.
Syntax
begin
#.. process
#..raise exception
rescue
# .. handle error
else
#.. executes if there is no exception
ensure
#.. finally ensure execution
#.. This will always execute.
end
Beispiel
begin
# raise 'A test exception.'
puts "I'm not raising exception"
rescue Exception => e
puts e.message
puts e.backtrace.inspect
else
puts "Congratulations-- no errors!"
ensure
puts "Ensuring execution"
end
Dies führt zu folgendem Ergebnis:
I'm not raising exception
Congratulations-- no errors!
Ensuring execution
Ausgelöste Fehlermeldung kann mit $ erfasst werden! Variable.
Fangen und werfen
Während der Ausnahmemechanismus von Erhöhen und Speichern großartig ist, um die Ausführung abzubrechen, wenn etwas schief geht, ist es manchmal schön, während der normalen Verarbeitung aus einem tief verschachtelten Konstrukt herausspringen zu können. Hier bieten sich Fangen und Werfen an.
Der catch definiert einen Block, der mit dem angegebenen Namen gekennzeichnet ist (dies kann ein Symbol oder eine Zeichenfolge sein). Der Block wird normal ausgeführt, bis ein Wurf auftritt.
Syntax
throw :lablename
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end
OR
throw :lablename condition
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end
Beispiel
Im folgenden Beispiel wird ein Wurf verwendet, um die Interaktion mit dem Benutzer zu beenden, wenn '!' wird als Antwort auf eine Eingabeaufforderung eingegeben.
def promptAndGet(prompt)
print prompt
res = readline.chomp
throw :quitRequested if res == "!"
return res
end
catch :quitRequested do
name = promptAndGet("Name: ")
age = promptAndGet("Age: ")
sex = promptAndGet("Sex: ")
# ..
# process information
end
promptAndGet("Name:")
Sie sollten das oben genannte Programm auf Ihrem Computer ausprobieren, da eine manuelle Interaktion erforderlich ist. Dies führt zu folgendem Ergebnis:
Name: Ruby on Rails
Age: 3
Sex: !
Name:Just Ruby
Klassenausnahme
Rubys Standardklassen und Module lösen Ausnahmen aus. Alle Ausnahmeklassen bilden eine Hierarchie, wobei die Klasse Exception oben steht. Die nächste Stufe enthält sieben verschiedene Typen -
- Interrupt
- NoMemoryError
- SignalException
- ScriptError
- StandardError
- SystemExit
Es gibt eine weitere Ausnahme auf dieser Ebene: Fatal, aber der Ruby-Interpreter verwendet dies nur intern.
Sowohl ScriptError als auch StandardError haben eine Reihe von Unterklassen, aber wir müssen hier nicht auf die Details eingehen. Wichtig ist, dass beim Erstellen eigener Ausnahmeklassen Unterklassen entweder der Klasse Exception oder einer ihrer Nachkommen sein müssen.
Schauen wir uns ein Beispiel an -
class FileSaveError < StandardError
attr_reader :reason
def initialize(reason)
@reason = reason
end
end
Schauen Sie sich nun das folgende Beispiel an, in dem diese Ausnahme verwendet wird:
File.open(path, "w") do |file|
begin
# Write out the data ...
rescue
# Something went wrong!
raise FileSaveError.new($!)
end
end
Die wichtige Zeile hier ist das Erhöhen von FileSaveError.new ($!) . Wir rufen Raise auf, um zu signalisieren, dass eine Ausnahme aufgetreten ist, und übergeben ihm eine neue Instanz von FileSaveError. Der Grund dafür ist, dass eine bestimmte Ausnahme das Schreiben der Daten fehlgeschlagen hat.