Enumerators

718 查看

注意:对于下面yielder这个对象,文档也没有说明,我自己的理解就是,该对象有一个实例方法,来指定迭代的内容。

triangular_number = Enumerator.new do |yielder|
      number = 0
      count = 1

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

require 'pp'

5.times do
  pp triangular_number.next
end

返回结果如下:
1
3
6
10
15

Enumerator对象实例可以完整的使用maxin Enumerable的所有方法,例如:to_a,first,take...

pp triangular_number.first 5
[1, 3, 6, 10, 15]

下面的例子:

fib = Enumerator.new do |yielder|
  a = 1
  b = 1
  loop do
    yielder.yield a
    a , b = b , a + b
  end
end

require 'pp'

#5.times { pp fib.next  }

#pp fib.take(10)

#我们通过Enumerator创建一个无限枚举对象,当然我们也可以
#传递一个Block生成一个新的Enumerator

def infinite_sleect(enum, &block)
  Enumerator.new do |yielder|
    enum.each do |value|
      yielder.yield value if block.call(value)
    end
  end
end

pp infinite_sleect(fib) { |value| value % 5 ==0 }.first(10)

下面的例子:

fib = Enumerator.new do |yielder|
  a = 1
  b = 1
  loop do
    yielder.yield a
    a , b = b , a + b
  end
end
require 'pp'
#更有意思的是我们可以在类Enumerator中定义一个方法,来继续迭代自身
class Enumerator
  def infinite_sleect(&block)
    Enumerator.new do |yielder|
      self.each do |value|
        yielder.yield value if block.call(value)
      end
    end
  end
end

pp fib
   .infinite_sleect { |value| value % 2 == 0 }
   .infinite_sleect { |value| value % 4 == 0 }
   .first(10)