Was ist der Unterschied zwischen "Raise" foo "und" Raise Exception.new ("foo") "?

103

Was ist der Unterschied - technisch, philosophisch, konzeptuell oder auf andere Weise - zwischen

raise "foo"

und

raise Exception.new("foo")

?

John Bachir
quelle

Antworten:

121

Technisch gesehen löst der erste einen RuntimeError mit der Nachricht auf "foo"und der zweite eine Ausnahme mit der Nachricht auf "foo".

In der Praxis gibt es einen signifikanten Unterschied zwischen dem Zeitpunkt, zu dem Sie den ersteren verwenden möchten, und dem Zeitpunkt, zu dem Sie den letzteren verwenden möchten.

Einfach gesagt, Sie wollen wahrscheinlich eine RuntimeErrornicht Exception. Ein Rettungsblock ohne Argument fängt RuntimeErrors, aber NICHT Exceptions. Wenn Sie also einen Exceptionin Ihrem Code auslösen, wird dieser Code ihn nicht abfangen:

begin
rescue
end

Um das zu fangen, müssen ExceptionSie Folgendes tun:

begin
rescue Exception
end

Dies bedeutet, dass a in gewissem Sinne Exceptionein "schlimmerer" Fehler ist als a RuntimeError, da Sie mehr Arbeit leisten müssen, um ihn zu beheben.

Was Sie wollen, hängt also davon ab, wie Ihr Projekt seine Fehler behandelt. In unseren Dämonen verfügt die Hauptschleife beispielsweise über eine leere Rettung, die sie fängt RuntimeErrors, meldet und dann fortsetzt. Aber unter ein oder zwei Umständen möchten wir, dass der Dämon wirklich wirklich bei einem Fehler stirbt, und in diesem Fall lösen wir einen aus Exception, der direkt durch unseren "normalen Fehlerbehandlungscode" und aus geht.

Und wieder, wenn Sie Bibliothekscode schreiben, möchten Sie wahrscheinlich einen RuntimeError, nicht einen Exception, da Benutzer Ihrer Bibliothek überrascht sein werden, wenn Fehler auftreten, die ein leerer rescueBlock nicht abfangen kann, und es einen Moment dauern wird, bis sie erkennen, warum.

Schließlich sollte ich sagen, dass das RuntimeErroreine Unterklasse der StandardErrorKlasse ist, und die eigentliche Regel ist, dass, obwohl Sie raise jede Art von Objekt können, das Leerzeichenrescue standardmäßig nur alles abfängt, von dem es erbtStandardError . Alles andere muss spezifisch sein.

Daniel Lucraft
quelle
2
sehr informativ, danke. ein paar Dinge: [1] Der letzte Absatz war die Beleuchtung, und lassen Sie mich bei irb etwas entdecken Sie nicht erwähnt: RuntimeError < StandardError < Exception[2] daher, dass der zweite Codeblock wird sowohl eine Ausnahme fangen und eine Runtime [3] Es ist interessant / seltsam, dass "nackte" Erhöhungen und Rettungen zufällig mit dieser bestimmten Ausnahme funktionieren [4]. Vielleicht lautet die Faustregel, RuntimeError auf Client-Code zu erhöhen, aber die eigenen benutzerdefinierten Ausnahmen innerhalb des eigenen Codes zu erhöhen und zu retten.
John Bachir
1
[1, 2] Ja. [3] nicht sicher ... [4] Wenn ich am professionellsten codiere, neige ich dazu, benutzerdefinierte Fehlertypen zu erstellen, von denen ich erbe StandardError. Es muss nicht komplizierter sein als ein paar Zeilen wie class MissingArgumentsError < StandardError; end.
Daniel Lucraft
Sehr informativ, aber in welchen Situationen möchten Sie eine Ausnahme anstelle eines Laufzeitfehlers auslösen, wenn ein Laufzeitfehler für das Schreiben von Libraray bevorzugt wird?
Chihung Yu
35

Aus der offiziellen Dokumentation:

raise   
raise( string )
raise( exception [, string [, array ] ] )

Löst ohne Argumente die Ausnahme in aus $!oder löst ein RuntimeErrorif aus, $!das null ist. Mit einem einzelnen StringArgument wird ein RuntimeErrormit der Zeichenfolge als Nachricht ausgelöst. Andernfalls sollte der erste Parameter der Name einer ExceptionKlasse sein (oder eines Objekts, das Exceptionbeim Senden eine Ausnahme zurückgibt ). Der optionale zweite Parameter legt die der Ausnahme zugeordnete Nachricht fest, und der dritte Parameter ist ein Array von Rückrufinformationen. Ausnahmen werden durch die Rettungsklausel von begin...endBlöcken erfasst.

raise "Failed to create socket"
raise ArgumentError, "No parameters", caller
ennuikiller
quelle