在Ruby中使用to_enum创建可枚举对象有什么好处?

Jas*_*son 14 ruby enumeration

为什么要使用to_enum方法而不是直接使用对象,在Ruby中创建对象的代理引用?我想不出任何实际用途,试图理解这个概念以及有人可能会使用它的地方,但我看到的所有例子都显得非常微不足道.

例如,为什么使用:

"hello".enum_for(:each_char).map {|c| c.succ }
Run Code Online (Sandbox Code Playgroud)

代替

"hello".each_char.map {|c| c.succ }
Run Code Online (Sandbox Code Playgroud)

我知道这是一个非常简单的例子,有没有人有任何现实世界的例子?

Mar*_*une 14

接受块的大多数内置方法将返回枚举器,以防没有提供块(如String#each_char您的示例中所示).对于这些,没有理由使用to_enum; 两者都会产生同样的效果.

但是,有些方法不会返回枚举器.在这种情况下,您可能需要使用to_enum.

# How many elements are equal to their position in the array?
[4, 1, 2, 0].to_enum(:count).each_with_index{|elem, index| elem == index} #=> 2
Run Code Online (Sandbox Code Playgroud)

再举一个例子,Array#product,#uniq#uniq!过去不接受块.在1.9.2中,这已被更改,但为了保持兼容性,没有块的表单无法返回Enumerator.人们仍然可以"手动"使用to_enum来获取枚举器:

require 'backports/1.9.2/array/product' # or use Ruby 1.9.2+
# to avoid generating a huge intermediary array:
e = many_moves.to_enum(:product, many_responses)
e.any? do |move, response|
  # some criteria
end 
Run Code Online (Sandbox Code Playgroud)

主要用途to_enum是在实现自己的迭代方法时.您通常会将第一行作为第一行:

def my_each
  return to_enum :my_each unless block_given?
  # ...
end
Run Code Online (Sandbox Code Playgroud)


mik*_*kej 1

这并不完全是您问题的答案,但希望它是相关的。

在第二个示例中,您each_char在不传递块的情况下进行调用。当没有块调用时each_char返回一个,Enumerator所以你的例子实际上只是做同一件事的两种方法。(即两者都会导致创建可枚举对象。)

irb(main):016:0> e1 = "hello".enum_for(:each_char)
=> #<Enumerator:0xe15ab8>
irb(main):017:0> e2 = "hello".each_char
=> #<Enumerator:0xe0bd38>
irb(main):018:0> e1.map { |c| c.succ }
=> ["i", "f", "m", "m", "p"]
irb(main):019:0> e2.map { |c| c.succ }
=> ["i", "f", "m", "m", "p"]
Run Code Online (Sandbox Code Playgroud)