这个问题不是关于如何在 Ruby 1.9.1 中使用枚举器,而是我很好奇它们是如何工作的。这是一些代码:
class Bunk
def initialize
@h = [*1..100]
end
def each
if !block_given?
enum_for(:each)
else
0.upto(@h.length) { |i|
yield @h[i]
}
end
end
end
在上面的代码中我可以使用e = Bunk.new.each
, 进而e.next
, e.next
获取每个连续的元素,但它到底是如何暂停执行然后在正确的位置恢复的呢?
我知道如果产量0.upto
被替换为Fiber.yield
那么就很容易理解了,但是这里不是这样的。这是一个普通的旧yield
, 那么它是怎样工作的?
我查看了 enumerator.c 但它对我来说几乎无法理解。也许有人可以在 Ruby 中提供一个实现,使用纤程,而不是 1.8.6 风格的基于连续的枚举器,这样一切就清楚了?
这是一个使用 Fibers 的普通 ruby 枚举器,其行为应该与原始枚举器非常相似:
class MyEnumerator
include Enumerable
def initialize(obj, iterator_method)
@f = Fiber.new do
obj.send(iterator_method) do |*args|
Fiber.yield(*args)
end
raise StopIteration
end
end
def next
@f.resume
end
def each
loop do
yield self.next
end
rescue StopIteration
self
end
end
如果有人对使用异常进行控制流感到不安:真正的枚举器也会在最后引发 StopIteration,所以我只是模拟原始行为。
Usage:
>> enum = MyEnumerator.new([1,2,3,4], :each_with_index)
=> #<MyEnumerator:0x9d184f0 @f=#<Fiber:0x9d184dc>
>> enum.next
=> [1, 0]
>> enum.next
=> [2, 1]
>> enum.to_a
=> [[3, 2], [4, 3]]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)