Enumerator :: Yielder#yield方法何时有用?

And*_*imm 14 ruby yield enumerable

这个问题提到了这个Enumerator::Yielder#yield方法.我之前没有使用它,我想知道在什么情况下它会有用.

当您想要创建无限的项目列表(例如Eratosthenes的Sieve)以及何时需要使用外部迭代器时,它是否主要有用?

Mla*_*vić 11

尽管构建无限列表和延迟迭代器非常方便,但我最喜欢的用法是将现有的Enumerable包含其他功能(任何可枚举的,无需知道它是什么,无论是否无限等).

简单的例子是实现each_with_index方法(或者更一般地说,with_index方法):

module Enumerable
  def my_with_index
    Enumerator.new do |yielder|
      i = 0
      self.each do |e|
        yielder.yield e, i
        i += 1
      end
    end
  end

  def my_each_with_index
    self.my_with_index.each do |e, i|
      yield e, i
    end
  end
end

[:foo, :bar, :baz].my_each_with_index do |e,i|
  puts "#{i}: #{e}"
end
#=>0: foo
#=>1: bar
#=>2: baz
Run Code Online (Sandbox Code Playgroud)

现在让我们扩展到在corelib :)中尚未实现的内容,例如将给定数组中的值循环分配给每个可枚举元素(例如,用于着色表行):

module Enumerable
  def with_cycle values
    Enumerator.new do |yielder|
      self.each do |e|
        v = values.shift
        yielder.yield e, v
        values.push v
      end
    end
  end
end

p (1..10).with_cycle([:red, :green, :blue]).to_a # works with any Enumerable, such as Range
#=>[[1, :red], [2, :green], [3, :blue], [4, :red], [5, :green], [6, :blue], [7, :red], [8, :green], [9, :blue], [10, :red]]
Run Code Online (Sandbox Code Playgroud)

整点是,这些方法返回Enumerator,然后您可以用通常的可枚举方法结合,如select,map,inject等.