加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读