在Ruby中提高异常与抛出异常有什么区别?

在Ruby中提高异常与抛出异常有什么区别?

What is the difference between Raising Exceptions vs Throwing Exceptions in Ruby?

Ruby有两种不同的异常机制:抛出/捕获和提升/救援。

为什么我们有两个?

你什么时候应该使用一个而不是另一个?


我认为http://hasno.info/ruby-gotchas-and-caveats可以很好地解释这种差异:

catch/throw are not the same as raise/rescue. catch/throw allows you to quickly exit blocks back to a point where a catch is defined for a specific symbol, raise rescue is the real exception handling stuff involving the Exception object.


  • raisefailrescueensure处理错误,也称为异常
  • throwcatch是控制流

Unlike in other
languages, Ruby’s throw and catch are not used for exceptions.
Instead, they provide a way to terminate execution early when no
further work is needed.
(Grimm, 2011)

使用简单的return可以终止单级控制流,如while循环。终止许多级别的控制流(如嵌套循环)可以使用throw来完成。

While the exception mechanism of raise and rescue is great for abandoning execution when things go wrong, it's sometimes nice to be able to jump out of some deeply nested construct during normal processing. This is where catch and throw come in handy.
(Thomas and Hunt, 2001)

工具书类

  • Grimm,Avdi。"扔、抓、举、救……我很困惑!"RubylLearning博客。N.P.,2011年7月11日。网状物。1一月2012日。http://rubylewinning.com/blog/2011/07/12/throw-catch-raise-rescue-im-so-mizzle/。
  • 托马斯、戴夫和安德鲁·亨特。"编程Ruby。":实用程序员指南。N.P.,2001。网状物。29九月2015日。http://ruby-doc.com/docs/programmingruby/html/tut_exceptions.html。

  • https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise提供了一个很好的解释,我怀疑我能改进。总而言之,我在博客上抓取了一些代码示例:

  • raise/rescue是与其他语言(或python的raise/except中所熟悉的throw/catch构造最接近的类似物。如果您遇到了一个错误条件,并且您将使用另一种语言对它执行throw,那么您应该使用ruby来执行raise

  • Ruby的throw/catch允许您中断执行并爬上堆栈查找catch(就像raise/rescue那样),但实际上并不适用于错误情况。它应该很少使用,只是当"向上移动堆栈直到找到对应的catch行为对于您正在编写的算法是有意义的,但是将throw视为对应于错误条件是没有意义的。

    在Ruby中,catch和throw用于什么?对throwcatch结构的良好使用提出了一些建议。

  • 它们之间的具体行为差异包括:

    • rescue Foo将拯救Foo的实例,包括Foo的子类。catch(foo)只捕获同一物体,Foo。您不仅不能通过catch类名称来捕获它的实例,而且甚至不能进行相等比较。例如

      1
      2
      3
      catch("foo") do
        throw"foo"
      end

      会给你一个UncaughtThrowError: uncaught throw"foo"(或者2.2之前的Ruby版本中的ArgumentError)

    • 可列出多个救援条款…

      1
      2
      3
      4
      5
      6
      7
      8
      begin
        do_something_error_prone
      rescue AParticularKindOfError
        # Insert heroism here.
      rescue
        write_to_error_log
        raise
      end

      虽然多个catche需要嵌套…

      1
      2
      3
      4
      5
      catch :foo do
        catch :bar do
          do_something_that_can_throw_foo_or_bar
        end
      end
    • 裸的rescue相当于rescue StandardError并且是惯用结构。"光秃秃的"catch,像catch() {throw :foo}一样,永远抓不到任何东西,不应该使用。


    推荐阅读