无法理解三元数枚举器良率

  • 本文关键字:三元 枚举 良率 ruby
  • 更新时间 :
  • 英文 :


无法理解这段代码是如何工作的。

triangular_numbers = Enumerator.new do |yielder|
number = 0
count = 1
loop do
number += count
count += 1
yielder.yield number  
end
end
5.times { print triangular_numbers.next, " " }

无法理解yielder如何用于此块。 它的yield如何number变量。 循环如何运行 5 次。 以及triangular_number.next如何首次工作。

枚举器基本上是你可以调用next并得到一些东西的东西。yielder是在调用next时返回某些内容的机制。执行在yield停止,直到下一次调用next

牵强的类比

您可以将enumerator想象成售票机,就像您在政府办公室排队等候一样。当你按下一个按钮(next)时,它会给你一张。在机器内部有一个滑槽,票从那里出来。但售票机并不是经常打印车票。它等待按下按钮,然后再打印下一张票并将其放入滑槽。

在这种情况下,类似的代码将是:

ticket_machine = Enumerator.new do |chute|
ticket = 0
loop do
#print_ticket
chute.yield ticket #waits here until you hit the button
ticket += 1
end
end
5.times { print ticket_machine.next, " " } # gets 5 tickets

您的代码示例基本上是相同的,但它不是发出票证,而是发出三角形数字。滑槽是数字传递的yielder

这不是使用枚举器的唯一方法,请查看文档以获取更多信息。

Enumerator::new接受一个块。这个块在运行时会收到一个Enumerator::Yielder,它有一个方法#yield

调用Enumerator#next时,将执行块,直到第一个Enumerator::Yielder#yield。执行在那里暂停;赋予yield的值是next返回的值。当您在同一Enumerator上再次调用next时,执行将恢复,并继续执行,直到再次遇到yield


因此,在您的情况下,5.times执行其块,打算重复五次。triangular_numbers.next被称为;这将开始执行上面的块。numbercount设置为它们的值,并启动无限循环。number设置为1count设置为2,然后我们找到yielder.yield。这会暂停块的执行,并将控件返回到循环中调用next5.times位置。next返回1,因为yielder.yield收到了number(1)。

第二次通过5.times循环,我们要打印下一个数字。这将停止主执行行,并从yielder.yield之后恢复枚举器块。无限循环继续;number3count3yielder.yield暂停枚举器并恢复主代码。next得到3,它被打印出来。

第三次、第四次和第五次通过5.times循环完全相同。

经过五次迭代后,5.times循环结束,执行继续通过它。枚举器暂停,准备按顺序给出下一个数字,如果您再次调用next(因为它具有无限循环),但您从未这样做,并且程序退出。

我将尝试一点一点地解释它的作用,以便您可以尝试围绕它。

Enumerator.new do |yielder|
end

因此,您实例化了一个枚举器,该枚举器将处理名为yielder的变量。

在其范围内,您可以设置一些本地变量(在重用对象时将保留这些变量):

number = 0
count = 1

然后你设置一个循环,number递增countcount递增1,然后调用 yield 通过你的参数传递number作为参数传递给它。

loop do
number += count
count += 1
yielder.yield number  
end

5.times重复传递给它的块 5 次。该块

-> { print triangular_numbers.next, " " }

调用print,它接受n参数并将各部分连接起来形成字符串,但不附加换行符。

第一个参数是我们的枚举器下一个交互 (triangular_numbers.next),它将计算隐式创建的Enumerator::Yielder上的当前数量和调用收益,将控件处理回调用Fiber以及传递给它的任何参数。

(所有枚举器在MRI上都作为"光纤"实现)

因此yielder.yield调用类似于Fiber.yield调用,并允许5.times循环运行并返回number1。

我在已经提供的清晰解释中添加一段代码:

my_enum = Enumerator.new do |whatever_name_for_the_yielder|
n = 0
loop do
whatever_name_for_the_yielder.yield "Return this: #{n}"
n += 1
end
end
puts my_enum.next #=> Return this: 0
puts my_enum.next #=> Return this: 1
puts my_enum.next #=> Return this: 2

当您提供迭代的结束时,它会停止并显示错误:

my_enum2 = Enumerator.new do |whatever_name_for_the_yielder|
2.times do |n|
whatever_name_for_the_yielder.yield "Return this: #{n}"
end
puts "Outside the loop"
end
puts my_enum2.next #=> Return this: 0
puts my_enum2.next #=> Return this: 1
puts my_enum2.next #=> Outside the loop
#=> ERROR: .....in `next': iteration reached an end (StopIteration)

最新更新