refs: http://railsware.com/blog/2012/03/13/ruby-2-0-enumerablelazy/ 这算是一次转载(翻译)吧!
曾经一度无限次的略过了 Enumerator::Lazy
,但蓦然回首间,发现它是多么的可爱!
我们从‘为什么’需要,来解释用它来干什么。
下面看个对比:
data.map(&:split).map(&:reverse)
data.map { |l| l.split.reverse }
这样的代码,我相信每个玩 ruby 的人都写过很多了。既然他们都是干“同样的事情”,那么我们肯定要选择一个优雅的 (elegant),自然第一种写法更符合这种需求。注意,前一句话中“同样的事情是打了引号的”,这里想强调的是,它们虽然结果是一样的,但是实现有很大不同。Ruby 是一门解释执行的语言,在解释器遇到第一种情况的时候,它将对 data 进行两次遍历,而第二种情况只会遍历一次。当这一次两次的差别遇到一个很大的数列的时候将会被无限放大,这必然不是我们想要见到的。
针对上面的假设,看下面的例子:
require 'prime'
Prime.select {|x| x % 4 == 3 }.take(10)
大家觉得上面的代码会花多长时间? 如果非要我告诉你一个答案的话,我希望是“一万年”! 但是毛主席说过“一万年太久 只争朝夕”,所以我们得改改才行:
a = []
Prime.each do |x|
next if x % 4 != 3
a << x
break if a.size == 10
end
那么对比之后我们会发现相对优雅的代码的问题所在,那就是 Prime 是一个无限大的数列,我们将会无限的等待下去,除非你给她一个‘break' !
等等,就这样了吗?第二种方案有点“丑觉不爱”,有木有?
当你有这个疑问的时候,是的!你应该需要Enumerator::Lazy
的安慰了!
Prime.lazy.select {|x| x % 4 == 3 }.take(10).to_a
PS: 此文仅仅举了些许简单的例子,欢迎大家给出更多的应用场景,让小生们开开眼界!