Ruby 中引发异常与抛出异常有什么区别?

问题描述 投票:0回答:3

Ruby 有两种不同的异常机制:Throw/Catch 和 Raise/Rescue。

为什么我们有两个?

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

ruby exception
3个回答
142
投票
  • raise
    fail
    rescue
    ensure
    处理错误,也称为异常
  • throw
    catch
    控制流

与其他不同 语言中,Ruby 的 throw 和 catch 不用于异常。 相反,它们提供了一种在没有任何结果时提前终止执行的方法。 还需要进一步的工作。 (格林,2011)

终止单级控制流(如

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

虽然raise和rescue的异常机制对于在出现问题时放弃执行非常有用,但有时在正常处理期间能够跳出某些深度嵌套的构造也很好。这就是 catch 和 throw 派上用场的地方。 (托马斯和亨特,2001)

参考文献

  1. 格林。 “扔、接住、举起、营救……我很困惑!” Ruby 学习博客。 N.p.,2011 年 7 月 11 日。网络。 2012 年 1 月 1 日。http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/
  2. 托马斯,亨特。 “红宝石编程。” :实用程序员指南。 N.p.,2001。网络。 2015 年 9 月 29 日。http://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html

116
投票

我认为http://hasno.info/ruby-gotchas-and-caveats对差异有一个很好的解释:

捕捉/投掷与举起/救援不同。 catch / throw允许您快速退出块回到为特定符号定义catch的点,引发救援是涉及Exception对象的真正异常处理内容。


23
投票

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

  1. raise
    /
    rescue
    是与您熟悉的其他语言中的
    throw
    /
    catch
    结构(或 Python 的
    raise
    /
    except
    )最接近的类似物。如果您遇到错误情况并且您会在其他语言中
    throw
    解决它,那么在 Ruby 中您应该
    raise

  2. Ruby 的

    throw
    /
    catch
    可以让你中断执行并爬上堆栈寻找
    catch
    (就像
    raise
    /
    rescue
    那样),但实际上并不是针对错误情况。它应该很少使用,并且只是在“沿着堆栈向上查找直到找到相应的
    catch
    ”行为对于您正在编写的算法有意义但考虑
    throw 没有意义时才存在。 
    对应于错误条件。

    catch 和 throw 在 Ruby 中的用途是什么? 提供了一些关于

    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
    

    同时需要嵌套多个

    catch
    ...

    catch :foo do
      catch :bar do
        do_something_that_can_throw_foo_or_bar
      end
    end
    
  • 裸露的

    rescue
    相当于
    rescue StandardError
    ,并且是一个惯用结构。 “裸露的
    catch
    ”,如
    catch() {throw :foo}
    ,永远不会捕获任何东西,因此不应该使用。

© www.soinside.com 2019 - 2024. All rights reserved.