Ruby 有两种不同的异常机制:Throw/Catch 和 Raise/Rescue。
为什么我们有两个?
什么时候应该使用一个而不是另一个?
raise
, fail
, rescue
, 和ensure
处理错误,也称为异常throw
并且catch
是控制流与其他语言不同,Ruby 的 throw 和 catch 不用于异常。相反,它们提供了一种在不需要进一步工作时提前终止执行的方法。(格林,2011)
while
可以使用简单的return
. 终止多层控制流,如嵌套循环,可以使用throw
.
虽然 raise 和 rescue 的异常机制非常适合在出现问题时放弃执行,但在正常处理期间能够跳出一些深度嵌套的构造有时会很好。这就是 catch 和 throw 派上用场的地方。(托马斯和亨特,2001)
我认为http://hasno.info/ruby-gotchas-and-caveats对差异有一个不错的解释:
接/投与举/救不同。catch/throw 允许您将块快速退出到为特定符号定义捕获的点,引发救援是涉及 Exception 对象的真正异常处理内容。
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise提供了一个很好的解释,我怀疑我可以改进。总而言之,我从博客文章中截取了一些代码示例:
raise
/是您从其他语言(或 Python 的/ )熟悉的/构造rescue
最接近的类似物。如果您遇到了错误情况并且您将使用另一种语言来解决它,那么您应该使用 Ruby。throw
catch
raise
except
throw
raise
Ruby 的throw
/catch
让你中断执行并爬上堆栈寻找catch
(like raise
/ rescue
dos),但实际上并不意味着错误条件。它应该很少使用,并且仅用于当“遍历堆栈直到找到相应的catch
”行为对您正在编写的算法有意义但将其throw
视为对应于错误是没有意义的健康)状况。
Ruby 中的 catch 和 throw 有什么用?throw
提供了一些关于/catch
构造的好用的建议。
它们之间的具体行为差异包括:
rescue Foo
将拯救Foo
包括Foo
. catch(foo)
只会捕获相同的对象,Foo
. 您不仅不能传递catch
类名来捕获它的实例,而且它甚至不会进行相等比较。例如
catch("foo") do
throw "foo"
end
会给你一个UncaughtThrowError: uncaught throw "foo"
(或ArgumentError
2.2 之前的 Ruby 版本)
可以列出多个救援条款...
begin
do_something_error_prone
rescue AParticularKindOfError
# Insert heroism here.
rescue
write_to_error_log
raise
end
而多个catch
es需要嵌套...
catch :foo do
catch :bar do
do_something_that_can_throw_foo_or_bar
end
end
一个barerescue
等价于rescue StandardError
并且是一个惯用的构造。“裸catch
”,如catch() {throw :foo}
,永远不会捕获任何东西,也不应该使用。