3

我很惊讶 Enumerator#each 没有从序列中的当前位置开始。

o = Object.new

def o.each
  yield 1
  yield 2
  yield 3
end

e = o.to_enum
puts e.next
puts e.next
e.each{|x| puts x}
# I expect to see 1,2,3 but I see 1,2,1,2,3
# apparently Enumerator's each (inherited from Enumerable) restarts the sequence!

我做错了吗?有没有办法构造另一个 Enumerator(来自 e),它将具有预期的每个行为?

4

2 回答 2

3

你没有做错,这不是为Enumerator#each. 您可以创建一个仅从当前位置迭代到结束的导数枚举器:

class Enumerator
  def enum_the_rest
    Enumerator.new { |y| loop { y << self.next } }
  end
end

o = Object.new
def o.each
  yield 1
  yield 2
  yield 3
end

e = o.to_enum
=> #<Enumerator: ...>
e.next
=> 1
e2 = e.enum_the_rest
=> #<Enumerator: ...>
e2.each { |x| puts x }
=> 2
=> 3

而且,顺便说一句,each不会重新启动序列,它总是在整个跨度上运行。您的枚举器仍然知道它与下一次next呼叫相关的位置。

e3 = o.to_enum
e3.next
=> 1
e3.next
=> 2
e3.map(&:to_s)
=> ["1", "2", "3"]
e3.next
=> 3
于 2013-05-05T19:41:40.353 回答
2

Enumerator#nextEnumerator#each以不同的方式处理对象。根据#each(强调我的)的文档:

根据此 Enumerable 的构造方式迭代块。如果没有给出块,则返回 self。

所以#each总是基于原始设置而不是当前的内部状态。如果您在源头上快速达到峰值,您会看到rb_obj_dup调用它来设置一个新的枚举器。

于 2013-05-05T19:48:46.323 回答