gpt4 book ai didi

ruby - 在 Ruby 中,实际上是如何从 Enumerator 对象中获取值的?

转载 作者:数据小太阳 更新时间:2023-10-29 07:47:29 25 4
gpt4 key购买 nike

我对如何从 Enumerator 对象中获取值很感兴趣。在下面的代码中,我期待第一个 enum.next 调用引发异常,因为在调用 之后已经从 enum 接收到所有值枚举.to_a.

enum = Enumerator.new do |yielder|
yielder.yield 1
yielder.yield 2
yielder.yield 3
end

p enum.to_a # => [1, 2, 3]

puts enum.next # Expected StopIteration here
puts enum.next
puts enum.next
puts enum.next # => StopIteration exception raised

Enumerator 的实例上调用 nextto_a 之类的迭代器方法有什么区别?

最佳答案

简答:to_a 总是遍历所有元素并且不推进迭代器的位置。这就是为什么 Enumerator#next即使您之前调用过 to_a,也会从第一个元素开始。调用 to_a 不会修改枚举器对象。


详情如下:

术语:内部迭代与外部迭代

在讨论 Ruby 中的迭代器时,会出现两个术语:

  1. internal iteration (也称为隐式迭代)
  2. external iteration

在您的问题中,enum.to_aenum 用于内部迭代的示例,而 enum.next 是外部迭代。

外部迭代提供了更多的控制,但它是一种更底层的操作。内部迭代通常更优雅。不同之处在于外部迭代使状态显式(当前位置),而内部迭代隐式应用于所有元素。

内部迭代:to_a

to_a 将调用 Enumerator#each ,它根据此枚举器的构造方式遍历 block 。

这是关键点。由于它不对调用它的枚举器对象的内部状态(位置)进行操作,它不会干扰对 next 的调用(外部迭代操作)。

外部迭代:下一步

当您创建 Enumerator 对象时,它的状态被初始化为指向第一个对象。您可以通过调用 next 来修改内部状态,这将使位置前进。一旦所有元素都被消耗掉,它将引发一个 StopIteration 异常。

请注意,仅当您使用枚举器对象进行外部迭代时,状态才相关。这解释了为什么您可以安全地对已经使用了所有元素的枚举器调用 to_a,并且它仍然会返回所有元素的列表。所有内部迭代操作(例如,eachto_a、map`)都不会干扰外部迭代。

在 Rubinius 中的实现

我查看了 Rubinius源代码以了解它是如何在那里实现的。虽然不是语言规范,但应该比较接近真相。入口点:

请注意,枚举器包括 Enumerable作为混合。

关于ruby - 在 Ruby 中,实际上是如何从 Enumerator 对象中获取值的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45200982/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com