在Ruby中使用to_enum创建可枚举对象的优点是什么?
为什么要在Ruby中通过使用to_enum方法而不是直接使用对象来创建对对象的代理引用?我想不出这有什么实际用途,试图理解这个概念&有人可能会在哪里使用它,但我看到的所有例子似乎都很琐碎 例如,为什么使用:在Ruby中使用to_enum创建可枚举对象的优点是什么?,ruby,enumeration,Ruby,Enumeration,为什么要在Ruby中通过使用to_enum方法而不是直接使用对象来创建对对象的代理引用?我想不出这有什么实际用途,试图理解这个概念&有人可能会在哪里使用它,但我看到的所有例子似乎都很琐碎 例如,为什么使用: "hello".enum_for(:each_char).map {|c| c.succ } 而不是 "hello".each_char.map {|c| c.succ } 我知道这是一个非常简单的例子,有人有真实世界的例子吗?这不是你问题的答案,但希望它是相关的 在第二个示例中,您在不
"hello".enum_for(:each_char).map {|c| c.succ }
而不是
"hello".each_char.map {|c| c.succ }
我知道这是一个非常简单的例子,有人有真实世界的例子吗?这不是你问题的答案,但希望它是相关的 在第二个示例中,您在不传递块的情况下调用每个字符。当在没有块的情况下调用时,每个字符都会返回一个枚举数,因此您的示例实际上只是做同一件事的两种方法。(即,两者都会导致创建可枚举对象。)
irb(main):016:0>e1=“hello”。枚举(:每个字符)
=> #
irb(main):017:0>e2=“你好”。每个字符
=> #
irb(main):018:0>e1.map{| c | c.such}
=>[“i”、“f”、“m”、“m”、“p”]
irb(main):019:0>e2.map{| c | c.such}
=>[“i”、“f”、“m”、“m”、“p”]
大多数接受块的内置方法都会在没有提供块的情况下返回枚举数(如示例中的String\each_char
)。对于这些,没有理由使用来枚举
;两者的效果相同
不过,有几个方法不返回枚举数。在这种情况下,您可能需要使用来_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
另一个例子是,Array#product
、#uniq
和#uniq代码>未用于接受块。在1.9.2中,对其进行了更改,但为了保持兼容性,没有块的表单不能返回枚举数。仍然可以“手动”使用进行枚举
获取枚举器:
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
to_enum
的主要用途是在实现自己的迭代方法时。您通常会将以下内容作为第一行:
def my_each
return to_enum :my_each unless block_given?
# ...
end
我认为这与内部和外部迭代器有关。返回如下所示的枚举数时:
p = "hello".enum_for(:each_char)
p是一个外部枚举数。外部迭代器的一个优点是:
外部迭代器比内部迭代器更灵活。例如,使用外部迭代器比较两个集合是否相等很容易,但使用内部迭代器实际上是不可能的…。但另一方面,内部迭代器更容易使用,因为它们为您定义了迭代逻辑。[摘自Ruby编程语言书,第5.3章]
因此,使用外部迭代器可以执行以下操作,例如:
p = "hello".enum_for(:each_char)
loop do
puts p.next
end
假设我们要获取一个键数组和一个值数组,并将它们缝合在一个散列中:
带#到#枚举
def hashify(k, v)
keys = k.to_enum(:each)
values = v.to_enum(:each)
hash = []
loop do
hash[keys.next] = values.next
# No need to check for bounds,
# as #next will raise a StopIteration which breaks from the loop
end
hash
end
没有#到#枚举:
def hashify(k, v)
hash = []
keys.each_with_index do |key, index|
break if index == values.length
hash[key] = values[index]
end
hash
end
读第一种方法要容易得多,你不觉得吗?不是很简单,但是想象一下如果我们以某种方式操纵3个数组中的项目?5.10?这对于大型或无限大的生成器对象非常有用。
例如,下面将为您提供整个斐波那契序列的枚举数,从0到无穷大
def fib_sequence
return to_enum(:fib_sequence) unless block_given?
yield 0
yield 1
x,y, = 0, 1
loop { x,y = y,x+y; yield(y) }
end
to_enum
有效地允许您使用常规的产量
编写此代码,而无需使用光纤
s
然后,您可以根据需要对其进行切片,这将非常节省内存,因为内存中不会存储任何数组:
module Slice
def slice(range)
return to_enum(:slice, range) unless block_given?
start, finish = range.first, range.max + 1
copy = self.dup
start.times { copy.next }
(finish-start).times { yield copy.next }
end
end
class Enumerator
include Slice
end
fib_sequence.slice(0..10).to_a
#=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
fib_sequence.slice(10..20).to_a
#=> [55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
如果您使用的是不返回枚举数的第三方库,那么它也很有用。使用next
会降低您的性能。两个示例处理大小差异的方式不同(一个升高,另一个停止)。
module Slice
def slice(range)
return to_enum(:slice, range) unless block_given?
start, finish = range.first, range.max + 1
copy = self.dup
start.times { copy.next }
(finish-start).times { yield copy.next }
end
end
class Enumerator
include Slice
end
fib_sequence.slice(0..10).to_a
#=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
fib_sequence.slice(10..20).to_a
#=> [55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]