raise“ foo”和raise Exception.new(“ foo”)之间有什么区别?


Answers:


121

从技术上讲,第一个引发消息设置为的RuntimeError,"foo"第二个引发消息设置为的Exception "foo"

实际上,何时使用前者和何时使用后者之间存在显着差异。

简而言之,您可能希望RuntimeError不要使用Exception。没有参数的救援块将捕获RuntimeErrors,但不会捕获Exceptions。因此,如果您Exception在代码中引发,则此代码将无法捕获它:

begin
rescue
end

为了赶上Exception您,您将必须执行以下操作:

begin
rescue Exception
end

从某种意义上讲,这意味着a Exception比a是“更糟糕”的错误RuntimeError,因为您必须做更多的工作才能从中恢复。

因此,您要取决于项目的错误处理方式。例如,在我们的守护程序中,主循环有一个空白的救援程序,它将捕获RuntimeErrors,报告它们,然后继续。但是在一种或两种情况下,我们希望守护程序确实真的因错误而死亡,在那种情况下,我们引发一个Exception,它直接通过我们的“常规错误处理代码”来回。

再说一次,如果您正在编写库代码,则可能需要一个RuntimeError,而不是一个Exception,因为库用户会因出现空白rescue块无法捕获的错误而感到惊讶,并且花了一些时间才意识到原因。

最后,我应该说RuntimeError是类的子StandardError类,实际规则是,尽管您可以使用raise 任何类型的对象,但rescue默认情况下,空白将仅捕获从继承的任何内容StandardError。其他所有内容都必须具体。


2
非常有用,谢谢。一些事情:[1]最后一段是最有启发性的,让我在irb上发现您没有提及的内容:RuntimeError < StandardError < Exception[2]因此,第二段代码将同时捕获Exception和RuntimeError [3]有趣/奇怪的是,“裸露”的引发和挽救恰好与特定的Exception [4]一起使用,也许经验法则是将RuntimeError引发给客户端代码,但是在自己的代码内部引发和挽救自己的自定义Exception?
约翰·巴希尔

1
[1,2]是的。[3]不确定... [4]当我以最专业的方式编码时,我倾向于创建继承自的自定义错误类型StandardError。它不一定要比的几行更复杂class MissingArgumentsError < StandardError; end
Daniel Lucraft

非常有用的信息,但是如果在编写libraray时首选运行时错误,那么在哪种情况下您将要引发Exception而不是运行时错误?
于洪雄

35

从官方文档中:

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

不带参数的情况下,在中引发异常,$!或者引发RuntimeErrorif $!is nil。仅使用单个String参数,它将RuntimeError使用字符串作为消息引发a 。否则,第一个参数应该是Exception类的名称(或返回发送Exception时异常的对象)。可选的第二个参数设置与异常关联的消息,第三个参数是回调信息数组。例外由以下内容的救援条款捕获:begin...end块。

raise "Failed to create socket"
raise ArgumentError, "No parameters", caller
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.