为什么在ruby中使用枚举器

时间:2016-03-06 21:32:13

标签: ruby

我偶然发现了这样的例子:

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}

那么这种结构的优点和缺点是什么?

2 个答案:

答案 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

当处理巨大或无限的序列时,差异非常重要。