产生或返回Enumerator的ruby方法

lev*_*lex 29 ruby enumerable

在Ruby的最新版本中,许多方法在没有块的情况下被调用时Enumerable返回Enumerator:

[1,2,3,4].map 
#=> #<Enumerator: [1, 2, 3, 4]:map> 
[1,2,3,4].map { |x| x*2 }
#=> [2, 4, 6, 8] 
Run Code Online (Sandbox Code Playgroud)

我想在我自己的方法中做同样的事情,如下:

class Array
  def double(&block)
    # ???
  end
end

arr = [1,2,3,4]

puts "with block: yielding directly"
arr.double { |x| p x } 

puts "without block: returning Enumerator"
enum = arr.double
enum.each { |x| p x }
Run Code Online (Sandbox Code Playgroud)

tok*_*and 29

核心库插入一个警卫return to_enum(:name_of_this_method, arg1, arg2, ..., argn) unless block_given?.在你的情况下:

class Array
  def double
    return to_enum(:double) unless block_given?
    each { |x| yield 2*x }
  end
end

>> [1, 2, 3].double { |x| puts(x) }
2
4
6 
>> ys = [1, 2, 3].double.select { |x| x > 3 } 
#=> [4, 6]
Run Code Online (Sandbox Code Playgroud)

  • 小注意:有时你的函数需要接受参数,所以只使用`:my_method`的`to_enum`将不起作用(因为当枚举枚举时,你的函数将被调用而没有参数).例如,如果这里的例子是`def mult_by(factor)... end`,你需要使用`to_enum(:my_method,factor)`. (7认同)

lev*_*lex 9

使用枚举器#new:

class Array
  def double(&block)
    Enumerator.new do |y| 
      each do |x| 
        y.yield x*2 
      end 
    end.each(&block)
  end
end
Run Code Online (Sandbox Code Playgroud)