Suche…


Ein grundlegender Fehlerbehandlungsblock

Lassen Sie uns eine Funktion erstellen, um zwei Zahlen zu teilen. Das ist sehr vertrauensvoll hinsichtlich der Eingabe:

def divide(x, y)
  return x/y
end

Dies wird bei vielen Eingaben gut funktionieren:

> puts divide(10, 2)
5

Aber nicht alles

> puts divide(10, 0)
ZeroDivisionError: divided by 0

> puts divide(10, 'a')
TypeError: String can't be coerced into Fixnum

Wir können die Funktion umschreiben, indem wir den riskanten Teilungsvorgang in einen begin... end Block einschließen, um nach Fehlern zu suchen, und eine rescue , um eine Nachricht auszugeben und bei Problemen nil .

def divide(x, y)
  begin
    return x/y
  rescue
    puts "There was an error"
    return nil
  end
end

> puts divide(10, 0)
There was an error

> puts divide(10, 'a')
There was an error

Fehler speichern

Sie können den Fehler speichern, wenn Sie ihn in der rescue möchten

def divide(x, y)
  begin
    x/y
  rescue => e
    puts "There was a %s (%s)" % [e.class, e.message]
    puts e.backtrace
  end
end

> divide(10, 0)
There was a ZeroDivisionError (divided by 0)
       from (irb):10:in `/'
       from (irb):10
       from /Users/username/.rbenv/versions/2.3.1/bin/irb:11:in `<main>'

> divide(10, 'a')
There was a TypeError (String can't be coerced into Fixnum)
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/workspace.rb:87:in `eval'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/workspace.rb:87:in `evaluate'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/context.rb:380:in `evaluate'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb.rb:489:in `block (2 levels) in eval_input'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb.rb:623:in `signal_status'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb.rb:486:in `block in eval_input'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/ruby-lex.rb:246:in `block (2 levels) in each_top_level_statement'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/ruby-lex.rb:232:in `loop'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/ruby-lex.rb:232:in `block in each_top_level_statement'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/ruby-lex.rb:231:in `catch'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/ruby-lex.rb:231:in `each_top_level_statement'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb.rb:485:in `eval_input'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb.rb:395:in `block in start'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb.rb:394:in `catch'
/Users/username/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb.rb:394:in `start'
/Users/username/.rbenv/versions/2.3.1/bin/irb:11:in `<main>'

Auf andere Fehler prüfen

Wenn Sie abhängig von der Art des Fehlers unterschiedliche Aktionen ausführen möchten, verwenden Sie mehrere rescue mit jeweils einem anderen Fehlertyp als Argument.

def divide(x, y)
  begin
    return x/y
  rescue ZeroDivisionError
    puts "Don't divide by zero!"
    return nil
  rescue TypeError
    puts "Division only works on numbers!"
    return nil
  end
end

> divide(10, 0)
Don't divide by zero!

> divide(10, 'a')
Division only works on numbers!

Wenn Sie den Fehler für die Verwendung im rescue speichern möchten:

rescue ZeroDivisionError => e

Verwenden Sie eine rescue ohne Argument, um Fehler eines Typs abzufangen, der nicht in einer anderen rescue ist.

def divide(x, y)
  begin
    return x/y
  rescue ZeroDivisionError
    puts "Don't divide by zero!"
    return nil
  rescue TypeError
    puts "Division only works on numbers!"
    return nil
  rescue => e
    puts "Don't do that (%s)" % [e.class]
    return nil
  end
end

> divide(nil, 2)
Don't do that (NoMethodError)

In diesem Fall ist der Versuch, nil durch 2 zu teilen, kein ZeroDivisionError oder TypeError wird er von der Standard- rescue , die eine Meldung NoMethodError , um uns NoMethodError , dass es sich um einen NoMethodError .

Wiederholen

In einer rescue können Sie erneut retry , die begin Klausel erneut auszuführen, vermutlich nachdem Sie den Umstand geändert haben, der den Fehler verursacht hat.

def divide(x, y)
  begin
    puts "About to divide..."
    return x/y
  rescue ZeroDivisionError
    puts "Don't divide by zero!"
    y = 1
    retry
  rescue TypeError
    puts "Division only works on numbers!"
    return nil
  rescue => e
    puts "Don't do that (%s)" % [e.class]
    return nil
  end
end

Wenn wir Parameter übergeben, von denen wir wissen, dass sie einen TypeError , wird die begin Klausel ausgeführt (hier mit dem Ausdruck "About to divide" gekennzeichnet), und der Fehler wird wie zuvor abgefangen und nil wird zurückgegeben:

> divide(10, 'a')
About to divide...
Division only works on numbers!
 => nil

Aber wenn wir Parameter übergeben , die eine verursachen ZeroDivisionError , die begin wird Klausel ausgeführt, der Fehler abgefangen wird, der Divisor von 0 auf 1 geändert, und dann retry Sie es begin retry Ursachen der begin Block wieder ausgeführt werden (von oben), jetzt mit ein verschiedene y . Beim zweiten Mal gibt es keinen Fehler und die Funktion gibt einen Wert zurück.

> divide(10, 0)
About to divide...     # First time, 10 ÷ 0
Don't divide by zero!
About to divide...     # Second time 10 ÷ 1
=> 10

Überprüfen, ob kein Fehler aufgetreten ist

Sie können eine else Klausel für Code verwenden, der ausgeführt wird, wenn kein Fehler auftritt.

def divide(x, y)
  begin
    z = x/y
  rescue ZeroDivisionError
    puts "Don't divide by zero!"
  rescue TypeError
    puts "Division only works on numbers!"
    return nil
  rescue => e
    puts "Don't do that (%s)" % [e.class]
    return nil
  else
    puts "This code will run if there is no error."
    return z
  end
end

Die else Klausel wird nicht ausgeführt, wenn ein Fehler auftritt, der die Kontrolle an eine der rescue überträgt:

> divide(10,0)
Don't divide by zero!
=> nil

Wenn jedoch kein Fehler auftritt, wird die else Klausel ausgeführt:

> divide(10,2)
This code will run if there is no error.
=> 5

Beachten Sie, dass die else Klausel nicht ausgeführt wird, wenn Sie von der begin Klausel zurückkehren

def divide(x, y)
  begin
    z = x/y
    return z                 # Will keep the else clause from running!
  rescue ZeroDivisionError
    puts "Don't divide by zero!"
  else
    puts "This code will run if there is no error."
    return z
  end
end

> divide(10,2)
=> 5

Code, der immer ausgeführt werden sollte

Verwenden Sie eine ensure , wenn es Code gibt, den Sie immer ausführen möchten.

def divide(x, y)
  begin
    z = x/y
    return z
  rescue ZeroDivisionError
    puts "Don't divide by zero!"
  rescue TypeError
    puts "Division only works on numbers!"
    return nil
  rescue => e
    puts "Don't do that (%s)" % [e.class]
    return nil
  ensure
    puts "This code ALWAYS runs."
  end
end

Die ensure Klausel wird ausgeführt, wenn ein Fehler auftritt:

> divide(10, 0)
Don't divide by zero!   # rescue clause
This code ALWAYS runs.   # ensure clause
=> nil

Und wenn kein Fehler vorliegt:

> divide(10, 2)
This code ALWAYS runs.   # ensure clause
=> 5

Die Sicherheitsklausel ist nützlich, wenn Sie beispielsweise sicherstellen möchten, dass Dateien geschlossen werden.

Beachten Sie, dass im Gegensatz zu der else Klausel, die ensure Klausel vor der Ausführung begin oder rescue Klausel gibt einen Wert. Wenn die ensure Klausel hat eine return , die den außer Kraft gesetzt wird return einer anderen Klausel!



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow