Ruby 枚举器yielder.yield VS.Proc.yield
我最近开始读《编程Ruby 1.9和2.0》一书。 它显示了显式枚举器的技巧Ruby 枚举器yielder.yield VS.Proc.yield,ruby,yield,enumerator,Ruby,Yield,Enumerator,我最近开始读《编程Ruby 1.9和2.0》一书。 它显示了显式枚举器的技巧 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, " "
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, " " }
puts
我想知道为什么这个yielder.yield会暂时离开循环,并在创建下一个枚举器对象之前返回number的值。这似乎不同于通常情况下,当一个屈服圈内块。我检查了APIdock,发现Proc.yield()的源代码与Proc.call()相同。对于枚举器类中的Yielder对象,Yielder已重写yield()。但是为什么yielder.yield会暂时离开循环块
参考:
,
您混淆了Ruby的yield语句与Enumerator::Yielder的yield方法和Proc的yield方法。它们可能拼写相同,但完全不同 陈述 收益表没有接收人。在方法内部,它意味着“立即运行块”。如果未附加块,则会发生错误。并不总是给它一个参数,因为有时您只想运行块
def foo
yield :bar
end
foo # LocalJumpError
foo { |x| puts x } # bar
枚举器::Yielder
对于一个yielder,
yield
几乎总是给出一个参数。这是因为它的意思与相同,我在书中也偶然发现了这个例子。
在仔细思考了示例的工作原理并浏览了Ruby doc之后,我找到了Fiber类,我认为这是枚举器在幕后使用的:
光纤概念实现了“轻量级协作并发”,这很有趣,不难理解,更重要的是,它与调用块或处理线程控件的其他“收益”不同
我认为枚举器有一个Fiber对象,它在其中传递到块。然后,每次在枚举器上调用“next”时,它都会在Fibre对象上调用“resume”以允许它计算下一个数字,而当块在Fibre上调用“yield”时,控件会返回到“next”方法。等等
以下是我的枚举器可能实现的版本(当然,仅限于本书示例中讨论的部分):
请看这里:如果您有任何问题,请告诉我。我想您可能会对统计员感到困惑。您说“直到创建下一个枚举器对象”,但这里只有一个枚举器:triangular\u numbers
。枚举数充当闭包,这就是为什么它可以在调用之间记住number
的值。读了这篇文章后,我尝试使用yield
而不是call,因为这听起来更好,但要注意,方法对象不会响应yield
。
Enumerator.new { |yielder| yielder.yield 3 }.next # 3
Enumerator.new { |yielder| yielder << 3 }.next # same thing
proc { |x| puts x }.yield(:bar) # bar
proc { |x| puts x }.call(:bar) # same thing as previous line
class MyExplicitEnumerator
def initialize (&block)
@yielder = Fiber.new { block.call Fiber }
end
def next
@yielder.resume
end
end
e = MyExplicitEnumerator.new do |yielder|
number = 1
loop do
yielder.yield number
number += 1
end
end
p e.next
p e.next
# output
# 1
# 2