在 Ruby 中引发异常和抛出异常的区别是什么?

Ruby 有两种不同的异常机制: 扔/捕捉和提高/拯救。

为什么我们有两个?

什么时候应该使用其中一种而不是另一种?

56853 次浏览

我认为 http://hasno.info/ruby-gotchas-and-caveats对这种差异有一个合理的解释:

抓/扔不同于加注/救援。Catch/throw 允许您快速退出块,返回一个为特定符号定义 catch 的点,提高拯救是涉及 Exception 对象的真正的异常处理工具。

  • raisefailrescueensure处理 错误,也称为 例外
  • throwcatch控制流程

不像其他人 语言,Ruby 的抛出和接住不用于异常。 相反,它们提供了一种方法,可以在没有 需要进一步的工作。 (格林,2011)

终止单一级别的控制流,如 while循环,可以通过一个简单的 return来完成。终止许多级别的控制流,比如嵌套循环,可以用 throw来完成。

虽然引发和拯救的异常机制非常适合在出错时放弃执行,但是有时候在正常处理过程中能够跳出一些深度嵌套的构造也是不错的。这时候接球和扔球就派上用场了。 (Thomas and Hunt,2001)

参考文献

  1. “扔,接,举,救... ... 我很困惑!”RubyLearning 博客,2011年7月11日,网站,2012年1月1日,http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/
  2. 《编程 Ruby 》 : 实用主义程序员指南,2001年,网络版,2015年9月29日,http://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html

Https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise 提供了一个很好的解释,我怀疑我能否改进。总而言之,在我写这篇博客的时候,我从中选取了一些代码示例:

  1. raise/rescue是与其他语言(或 Python 的 raise/except)中您所熟悉的 throw/catch结构最接近的类似物。如果您遇到了一个错误条件,并且您将使用另一种语言通过它执行 throw,那么您应该使用 Ruby 中的 raise

  2. Ruby 的 throw/catch允许您中断执行并爬上堆栈查找 catch(就像 raise/rescue一样) ,但是并不真正用于错误条件。它应该很少被使用,而且只是在“沿着栈走,直到找到相应的 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"(或者2.2之前 Ruby 版本的 ArgumentError)

  • 可以列出多个营救条款..。

    begin
    do_something_error_prone
    rescue AParticularKindOfError
    # Insert heroism here.
    rescue
    write_to_error_log
    raise
    end
    

    而多个 catchs 需要嵌套..。

    catch :foo do
    catch :bar do
    do_something_that_can_throw_foo_or_bar
    end
    end
    
  • A bare rescue is equivalent to rescue StandardError and is an idiomatic construct. A "bare catch", like catch() {throw :foo}, will never catch anything and shouldn't be used.