在Ruby中引发异常与引发异常之间有什么区别?


Answers:


104

我认为http://hasno.info/ruby-gotchas-and-caveats对区别有一个不错的解释:

抓/掷与加/抢不同。catch / throw允许您快速退出块,回到为特定符号定义catch的地步,引发抢救是涉及Exception对象的真正的异常处理工作。


1
好奇地知道...从iPad上读取此内容,因此无法在1.9中对其进行测试,但是其中一些陷阱在最近的红宝石版本中不再有效,对吗?
Denis de Bernardy 2011年

12
还值得知道:raise非常昂贵。throw不是。想想throw作为使用goto以获得循环了。
docwhat 2012年

4
@Denis您指的是什么陷阱?
docwhat

1
链接断开了!
morhook

请参阅ruby的抛出和效率,以了解更多有关性能差异的信息。
富兰克林于

109
  • raisefailrescue,和ensure手柄的错误,也被称为异常
  • throwcatch控制流

与其他语言不同,Ruby的throw和catch不用于异常。相反,它们提供了一种在不需要进一步工作时及早终止执行的方法。(格林,2011年)

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

虽然引发异常的异常机制非常适合在出现问题时放弃执行,但是有时可以在正常处理过程中跳出一些深层嵌套的构造,这是很好的选择。这是捕捉和投掷派上用场的地方。(Thomas和Hunt,2001)

参考资料

  1. 格林,阿夫迪。“投掷,接住,提升,救援……我很困惑!” RubyLearning博客。NP,2011年7月11日。网站。2012年1月1日。http ://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/
  2. 托马斯,戴夫和安德鲁·亨特。“编程Ruby。” :《实用程序员指南》。Np,2001年。Web。2015年9月29日。http ://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html

2
Avdi并没有像他在播客的声音。
hrdwdmrbl 2013年

2
Ruby Learning链接似乎无效。这是另一篇讨论差异的博客文章:danielchangnyc.github.io/blog/2013/10/23/throw-raise
Dennis

有趣的是,rubylearning.com认为Avdi的文章仍然存在。我想这就是我们将内容复制到SO的原因,因此它不会丢失!
Jared Beck

21

https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise提供了一个很好的解释,我怀疑我可以改进。总而言之,在我走时从博客文章中切出一些代码示例:

  1. raise/ rescue是您从其他语言(或Python的/ )熟悉的throw/ catch构造最接近的类似物。如果遇到错误情况,并且会用另一种语言进行处理,则应该使用Ruby。raiseexceptthrowraise

  2. Ruby的throw/ catch可以让您中断执行并爬上堆栈以查找catch(像raise/ rescue确实一样),但这并不是真正意义上的错误条件。它应该很少使用,仅当“走到栈上直到找到对应的catch”行为对您正在编写的算法有意义,但认为与throw错误对应的意义就不大了健康)状况。

    Ruby中的catch和throw用途是什么?提供了一些有关throw/ catch构造好的用法的建议。

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

  • rescue Foo将挽救Foo包含的子类的实例Foocatch(foo)只会捕获相同的对象Foo。您不仅不能传递catch类名来捕获它的实例,而且甚至不进行相等比较。例如

    catch("foo") do
      throw "foo"
    end

    将为您提供UncaughtThrowError: uncaught throw "foo"(或ArgumentError2.2之前的Ruby版本)

  • 可以列出多个救援条款...

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

    而多个catches需要嵌套...

    catch :foo do
      catch :bar do
        do_something_that_can_throw_foo_or_bar
      end
    end
  • 裸露rescue等同于rescue StandardError并且是惯用语。catch像这样的“裸露” catch() {throw :foo}永远不会捕获任何东西,因此不应该使用。


好的解释却引出了一个问题,为什么他们会在地球上设计红宝石=用其他语言抛出。然后还包含throw但其他语言中则包含!= throw。我在那里看不到他们的原始逻辑
00:00有线

@ wired00 耸耸肩)。我同意,与当今其他流行语言相比,它似乎很古怪。
Mark Amery

2
@ wired00:自从1960年代首次对结构化错误处理进行实验以来,它就被称为“引发”异常,在发明了现代形式的异常处理的开创性文章中,它被称为“引发”异常。在Lisps和Smalltalks中“引发”异常是Ruby的主要灵感,它被称为“引发”异常或“引发”硬件中断,在硬件中,该概念甚至早于“编程”概念就已经存在。语言”。问题应该是:那些其他语言为什么会改变这种状况?
约尔格W¯¯米塔格

@MarkAmery:请记住,许多其他“流行语言” 都比Ruby还要年轻,或者至少是当代的。因此,问题应该是:为什么那些其他语言没有遵循Ruby(以及Smalltalk和Lisp以及硬件和文献)。
约尔格W¯¯米塔格

@JörgWMittag有趣的是-您启发了我进行一些历史研究。C ++的想法是在Ruby出现之前的几年就“抛出”异常,而且根据english.stackexchange.com/a/449209/73974,该术语实际上可以追溯到70年代……所以我认为我们仍然要批评Ruby采用既定的术语并用它来表示完全不同的东西。
Mark Amery
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.