就是快速退出好几个循环区块:
result = catch(:halt) do
(1..12).each { |i|
(1..3).each { |t|
throw :halt, 4 if i == 4
}
}
-1
end
puts result
里面 throw 结果,外面 catch 得到结果。 原先我一直用其他的方法来处理,这次终于看到好方法了。 这个东西我是在 sinatra 源码里面发现的,看源码好处多多~
更多介绍见:http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue-im-so-confused/
第一次知道这个用法,毫无疑问用 throw / catch 跳出嵌套循环干净利索,不过从可读性和表达性上看,这个用法在 Rubyist 中可能很难流行吧。
引用的文章中的评论也有亮点,特别是这篇 Dont Use Exceptions For Flow Control 中还特别提到了 Ruby 的这种用法:
The RubyLanguage has separate mechanisms for reporting errors and UnwindingTheStack as flow control. The begin...rescue and raise statements are used for reporting and handling methods. The throw...catch statements are used for unwinding deeply nested calls.
@linjunhalida 异常捕获机制通常比较复杂,某些语言会采用 CPU 陷阱等,这会导致实际捕获成本非常的高,所以一般语言并不推荐异常作为控制流的方法。
warden 也用了 throw 和 catch.
你可以在 rack 的 warden middleware 上层直接丢个 :warden 出来,然后 warden 就帮你返回 401 了
https://github.com/hassox/warden/wiki/Overview#failing-authentication
在 Ruby 语言层面,异常处理是 begin,rescue,raise。而 throw 和 catch 则是用于流程控制。Ruby 中的 throw 和 catch 在语言层面上 与 java 的,是两种不同的东东。
Ruby 学 Smalltalk,要让控制流以库而不是关键字的形式提供,才用了类似抛错的机制。你可以认为其实 break/return 什么的也是会 throw 的。
Rust,不像 Ruby 有 block 和 lambda 两种不同的语义。Rust 只有 lambda,并且是通过不同的返回值来实现不同的控制流,最后通过编译期对 lambda 的统一优化来消除额外的运行期开销。
catch ... throw 不是异常处理的方法(很多人误会),是 Ruby 给你一个机制,帮助你在可能估计到的异常爆发之前跳出,控制权交到 Rubyist 手里。这是一种超越了异常处理的机制,也很符合 Ruby 语言一贯的设计原则。 「诱人的 Ruby」入门视频 http://edu.51cto.com/lesson/id-10743.html 中第 46 分钟以后,有代码示例,欢迎讨论。