我偶然发现了这样的例子:
file = "./path"
var = Enumerator.new do |y|
CSV.foreach(file) do |row|
y.yield(row)
end
end
问题是,为什么存储数组中的任何类型的数据,在枚举数内?上面和上面的行为有什么不同:
file = "./path"
var = []
CSV.foreach(file) do |row|
var << row
end
当我想要使用数据时,两种情况看起来都是一样的:
var.each {|row| puts row}
那么这种结构的优点和缺点是什么?
答案 0 :(得分:4)
通常,迭代器可用于懒惰地生成一系列对象。 与创建更高效的项集合相比,这是创建延迟枚举时的主要优势。
例如,如果您的枚举器循环仅迭代300万个项目的前5个项目,那么所有产品都会返回,并且您在内部首先没有构建100万个项目的集合。
因此,您不需要加载所有300万个项目,只是因为您的被调用函数可以继续并执行其余的代码。
迭代器是返回序列的手段。
有时序列甚至可能无限。
它将懒惰评估的函数式编程概念引入Ruby - 至少对于枚举。
返回集合和返回集合生成器之间存在巨大差异。
答案 1 :(得分:0)
看到代码的不同,在循环中添加puts
。
seq = (1..3)
enum = Enumerator.new do |y|
seq.each do |i|
puts "Grabbing #{i} with enumerator"
y.yield(i)
end
end
enum.each { |i| puts "Taken #{i} from enumerator" }
# Grabbing 1 with enumerator
# Taken 1 from enumerator
# Grabbing 2 with enumerator
# Taken 2 from enumerator
# Grabbing 3 with enumerator
# Taken 3 from enumerator
array = []
seq.each do |i|
puts "Grabbing #{i} with array"
array << i
end
array.each { |i| puts "Taken #{i} from array" }
# Grabbing 1 with array
# Grabbing 2 with array
# Grabbing 3 with array
# Taken 1 from array
# Taken 2 from array
# Taken 3 from array
像Tal Avissar所提到的,Enumerator
在需要时获取值,称为懒惰评估。在某些情况下,这种行为是有益的。
# infinite number sequence
numbers = Enumerator.new do |y|
n = 0
loop { y.yield(n += 1) }
end
puts numbers.take(3).join(', ')
# 1, 2, 3
当处理巨大或无限的序列时,差异非常重要。