Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 枚举器yielder.yield VS.Proc.yield_Ruby_Yield_Enumerator - Fatal编程技术网

Ruby 枚举器yielder.yield VS.Proc.yield

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, " "

我最近开始读《编程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, " " }
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