Ruby中的catch和throw在哪里有用?

时间:2010-01-07 04:03:04

标签: ruby

我真的没有看到这些的合理使用。已有rescueraise,为什么需要throwcatch?似乎它们应该被用来跳出深深的嵌套,但这对我来说只是闻起来像。是否有任何良好,干净的使用例子?

4 个答案:

答案 0 :(得分:6)

注意:看起来好像1.9中的catch / throw已经改变了一些。这个答案适用于Ruby 1.9。

一个很大的区别是,您可以throw提供任何内容,而不仅仅是StandardError派生的内容,与raise不同。像这样愚蠢的东西是合法的,例如:

throw Customer.new

但它并不是非常有意义。但你做不到:

irb(main):003:0> raise Customer.new
TypeError: exception class/object expected
    from (irb):3:in `raise'
    from (irb):3
    from /usr/local/bin/irb:12:in `<main>'

答案 1 :(得分:5)

通过将控制权移出DSL而无需复杂的case / if语句,它们可以真正用于简化最终用户的DSL

我有一个Ruby应用程序,允许用户通过内部DSL扩展它。 DSL中的某些功能需要将控制权返回给我的应用程序的特定部分。我们举一个简单的例子。假设用户正在开发一个关于日期的简单扩展

if today is a holiday then
   do nothing
end

week_of_year = today.week.number

if week_of_year < 10 then

...

do nothing位触发一个throw,它将控制权交给exec语句并返回给我。

在某些情况下,我们希望它退出并将控制权交还给我的应用程序,而不是继续执行DSL。现在,您可以让用户使用大量嵌入式if语句,让DSL自然结束,但这只是模糊了逻辑试图说的内容。

投掷确实是一个被认为是“危险”的转移,但该死的有时它们是最好的解决方案。

答案 2 :(得分:2)

它基本上是一个goto,稍微类似于call / cc,除了控制流是通过名称隐式连接而不是显式地作为参数连接。 throw / catch和raise / rescue之间的区别在于前者旨在用于控制流而不仅仅是特殊情况,并且它不会浪费时间将堆栈跟踪放在一起。

Sinatra对HTTP错误代码使用throw / catch,其中处理程序可以使用throw以结构化方式将控制权交给Sinatra库。其他类型的HTTP框架使用异常,或者通过返回不同类的响应,但这会让Sinatra(例如)在捕获它之后尝试另一个请求处理程序。

答案 3 :(得分:1)

两者之间的区别在于你只能“提高”异常,但可以“抛出”任何东西(1.9)。除此之外,它们应该是可以互换的,也就是说,应该可以用另一个重写一个,就像@ john-feminella给出的例子一样。