Ruby枚举器如何终止迭代?

Ruby枚举器如何终止迭代?,ruby,enumerable,enumerator,take,Ruby,Enumerable,Enumerator,Take,朋友们,请帮我解释一下:在下面的Ruby代码中,白蚁循环的作用是什么?它应该是一个无限循环,但是,它是如何终止的呢 # Ruby code fib = Enumerator.new do |y| a = b = 1 loop do y << a a, b = b, a + b end end p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] #Ruby代码 fib=枚举数。新do | y

朋友们,请帮我解释一下:在下面的Ruby代码中,白蚁循环的作用是什么?它应该是一个无限循环,但是,它是如何终止的呢

# Ruby code
fib = Enumerator.new do |y|
  a = b = 1
  loop do
    y << a
    a, b = b, a + b
  end
end

p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
#Ruby代码
fib=枚举数。新do | y|
a=b=1
环道
y[1,1,2,3,5,8,13,21,34,55]
非常感谢您的贡献。

(来源:)

您实现函数fib的方式允许它“懒惰”。这意味着Ruby在绝对必要之前不会尝试计算fib中的值

最后一行的
take
方法是这里的关键

p fib.take(10) 
基本上,Ruby说“我将评估
fib
的前10个值,并假装其余的值不存在,因为我还不必使用它们。”

换句话说,虽然
fib
函数可能是无限的,但您只要求前10个值,因此您只得到了前10个值

如果您尝试过类似的方法:

p fib.to_a
你的程序会被卡住。为什么?因为
to_a
(to array)方法想要尝试获取所有fib的值,而不仅仅是其中的一部分。显然,您无法获得无限列表的所有值

有关更多信息:

---编辑:---

技术修正:正如Cary Swoveland指出的那样,如果说
fib
是一种按需生成值的算法/机器,那么在技术上更为正确

枚举器就像一个按钮,每次按下分配器顶部时,它都会弹出一颗薄荷糖。计数型的自动售货机不会供应糖果,但会根据需要一次生产一种糖果,可能能够生产无限数量的糖果

一种类型的枚举数绑定到底层对象集合。这里有两个绑定到一个数组

enum = [1,2,3].each #=> #<Enumerator: [1, 2, 3]:each> 

enum.next #=> 1 
enum.next #=> 2 
enum.next #=> 3 
enum.next #=> StopIteration (iteration reached an end) 
enum=[1,2,3]。每个#=>
enum.next#=>1
enum.next#=>2
enum.next#=>3
enum.next#=>停止迭代(迭代已结束)

enum=[1,2,3]。循环#=>#
enum.next#=>1
enum.next#=>2
enum.next#=>3
enum.next#=>1
enum.next#=>2
... 无限远
枚举第一(8)
#=> [1, 2, 3, 1, 2, 3, 1, 2] 
在第一个示例中,在引发
StopIteration
异常之前,枚举器只生成有限数量的对象。在第二个示例中,可以生成任意数量的对象,但只能根据需要生成<例如,code>first指示
enum
8次生成一个对象并将其传递给自身<代码>枚举
不懒惰;它渴望遵守,但在得到指示之前不会制造和分发物品


另一种类型的枚举器根据一组与生俱来的规则生成对象,这些规则与基础对象无关。这些枚举器通常能够生成无限多个对象。生成斐波那契数的枚举数就是该类型枚举数的一个示例。它不是一个不终止的循环;它是一种能够根据需要生产任意数量的物体,但一次只能生产一个物体的机器

另一方面,在Ruby v2.7中,Ruby monks赋予了我们一种方法,它简化了一些枚举数的创建,包括生成斐波那契数的枚举数:
enum=Enumerator.product([0,1]){n1,n2 |[n2,n2+n1]}
。例如,前8个斐波那契数由
arr=enum.take(8)#=>[[0,1]、[1,1]、[1,2]、[2,3]、[3,5]、[5,8]、[8,13]、[13,21]
给出,然后是
arr.map(&:first)#=>[0,1,1,2,3,5,8,13]
enum = [1,2,3].cycle #=> #<Enumerator: [1, 2, 3]:cycle> 

enum.next #=> 1 
enum.next #=> 2 
enum.next #=> 3 
enum.next #=> 1 
enum.next #=> 2 
... ad infinitum

enum.first(8)
  #=> [1, 2, 3, 1, 2, 3, 1, 2]