Ruby 今天发现一个以前没有注意到的好用的 ruby 语法,分享一下

linjunhalida · 2013年12月21日 · 最后由 whitecrow 回复于 2013年12月22日 · 5929 次阅读

就是快速退出好几个循环区块:

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.

不建义使用“异常”跳出执行流,这会带来一些性能问题 可以使用 break 来跳出 each

#3 楼 @hysios 看了一下,好像真是创建了一个异常对象。这个我觉得应该可以优化的吧。。

./vm_eval.c:

th->errinfo = NEW_THROW_OBJECT(tag, 0, TAG_THROW);

@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 没搞对的地方,这个就是 Rust 搞对的地方 ...

#8 楼 @bhuztez rust 怎么实现的?

#9 楼 @linjunhalida

Ruby 学 Smalltalk,要让控制流以库而不是关键字的形式提供,才用了类似抛错的机制。你可以认为其实 break/return 什么的也是会 throw 的。

Rust,不像 Ruby 有 block 和 lambda 两种不同的语义。Rust 只有 lambda,并且是通过不同的返回值来实现不同的控制流,最后通过编译期对 lambda 的统一优化来消除额外的运行期开销。

参考 http://lucumr.pocoo.org/2012/10/18/such-a-little-thing/

#4 楼 @linjunhalida 你的“./vm_eval.c”是怎么调试出来的呀?好神奇。(● _ ●)

catch ... throw 不是异常处理的方法(很多人误会),是 Ruby 给你一个机制,帮助你在可能估计到的异常爆发之前跳出,控制权交到 Rubyist 手里。这是一种超越了异常处理的机制,也很符合 Ruby 语言一贯的设计原则。 「诱人的 Ruby」入门视频 http://edu.51cto.com/lesson/id-10743.html 中第 46 分钟以后,有代码示例,欢迎讨论。

#11 楼 @whitecrow grep 源码啊。。。顺藤摸瓜。。

#13 楼 @linjunhalida 你这是 C 文件,是 grep CRuby 本身的源代码?

@linjunhalida 学到了一招,犀利呀~~

需要 登录 后方可回复, 如果你还没有账号请 注册新账号