Ruby的Enumerator对象如何在内部迭代器上进行外部迭代?
发布时间:2020-12-17 03:35:55 所属栏目:百科 来源:网络整理
导读:根据 Ruby的文档,如果没有为to_enum或enum_for方法提供目标方法,则Enumerator对象使用每个方法(枚举).现在,我们以下面的猴子补丁及其枚举器为例 o = Object.newdef o.each yield 1 yield 2 yield 3ende = o.to_enumloop do puts e.nextend 鉴于Enumerator对
根据
Ruby的文档,如果没有为to_enum或enum_for方法提供目标方法,则Enumerator对象使用每个方法(枚举).现在,我们以下面的猴子补丁及其枚举器为例
o = Object.new def o.each yield 1 yield 2 yield 3 end e = o.to_enum loop do puts e.next end 鉴于Enumerator对象在调用next时使用每个方法来回答,每次调用next时,如何调用每个方法? Enumeartor类是否预先加载o.each的所有内容并为枚举创建本地副本?或者是否有某种Ruby魔法在每个yield语句中挂起操作,直到在enumeartor上调用next? 如果制作了内部副本,它是否是深层副本?那些可以用于外部枚举的I / O对象呢? 我正在使用Ruby 1.9.2. 解决方法
它并不完全是魔术,但它仍然是美丽的.不使用某种类型的副本,而是使用
Fiber 首先在目标可枚举对象上执行每个副本.在接收到每个物体的下一个物体后,光纤产生该物体,从而将控制返回到最初恢复光纤的位置.
它很漂亮,因为这种方法不需要可枚举对象的副本或其他形式的“备份”,因为可以想象通过例如在可枚举上调用#to_a来获得.使用光纤的协作调度允许在需要时准确地切换上下文,而无需保持某种形式的前瞻. 这一切都发生在C code的枚举器中.一个显示大致相同行为的纯Ruby版本可能如下所示: class MyEnumerator def initialize(enumerable) @fiber = Fiber.new do enumerable.each { |item| Fiber.yield item } end end def next @fiber.resume || raise(StopIteration.new("iteration reached an end")) end end class MyEnumerable def each yield 1 yield 2 yield 3 end end e = MyEnumerator.new(MyEnumerable.new) puts e.next # => 1 puts e.next # => 2 puts e.next # => 3 puts e.next # => StopIteration is raised (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |