2010-07-20 120 views
150

我刚刚对Ruby中的循环提出了一个问题。这两种迭代集合的方式是否有区别?“for”vs“each”in Ruby

# way 1 
@collection.each do |item| 
    # do whatever 
end 

# way 2 
for item in @collection 
    # do whatever 
end 

或只是想知道,如果这些是完全一样的,如果可能有细微的差别(可能时@collection为零)。

回答

249

这是唯一的区别:

每个:

irb> [1,2,3].each { |x| } 
    => [1, 2, 3] 
irb> x 
NameError: undefined local variable or method `x' for main:Object 
    from (irb):2 
    from :0 

为:

irb> for x in [1,2,3]; end 
    => [1, 2, 3] 
irb> x 
    => 3 

随着for循环中,迭代变量仍然住后的块是完成。使用each循环,它不会,除非在循环开始之前它已经被定义为局部变量。

除此之外,for只是each方法的语法糖。

@collectionnil两个环抛出异常:

例外:未定义局部变量或方法`@collection”的主要:对象

25

你的第一个例子,

@collection.each do |item| 
    # do whatever 
end 

is more idiomatic。虽然Ruby支持像forwhile这样的循环结构,但块语法通常是首选。

另一个细微的区别是,您在for循环内声明的任何变量都将在循环外部可用,而迭代器块中的变量实际上是私有的。

0

据我所知,使用块代替语言中的控制结构更具惯用性。

2

看起来没有区别,for使用下面的each

$ irb 
>> for x in nil 
>> puts x 
>> end 
NoMethodError: undefined method `each' for nil:NilClass 
    from (irb):1 
>> nil.each {|x| puts x} 
NoMethodError: undefined method `each' for nil:NilClass 
    from (irb):4 

就像贝亚德说的,每一种都更加地道。它隐藏了更多的内容,不需要特殊的语言功能。 每特勒马库斯的评论

for .. in ..设置环路范围之外的迭代器,所以

for a in [1,2] 
    puts a 
end 

离开a循环结束之后确定。 each没有。这是支持使用each的另一个原因,因为临时变量的寿命较短。

+1

关于可变范围,存在一个小的差异(如yjerem,ChristopheD和Bayard提到)。 – Telemachus 2010-07-20 21:56:39

+0

不正确,'for'不在下面使用'each'。查看其他答案。 – akuhn 2016-12-23 22:27:48

+0

@akuhn有关进一步的说明,请参阅此[问题](http://stackoverflow.com/q/39839809/5101493)及其优秀答案。 – 2016-12-28 13:56:06

41

请参阅“The Evils of the For Loop”以获得很好的解释(考虑到变量作用域,有一个小差异)。

使用eachconsidered more idiomatic使用Ruby。

+0

@zachlatta:感谢您的通知。我将编辑链接以指向文章的webarchive.org变体! – ChristopheD 2013-04-08 22:47:17

+1

http://graysoftinc.com/early-steps/the-evils-of-the-for-loop是新的链接,现在JEG2的网站重新上线了。 – pnomolos 2014-06-11 23:32:57

5

一个以上不同..

number = ["one", "two", "three"] 
=> ["one", "two", "three"] 

loop1 = [] 
loop2 = [] 

number.each do |c| 
    loop1 << Proc.new { puts c } 
end 
=> ["one", "two", "three"] 

for c in number 
    loop2 << Proc.new { puts c } 
end 
=> ["one", "two", "three"] 

loop1[1].call 
two 
=> nil 

loop2[1].call 
three 
=> nil 

来源:http://paulphilippov.com/articles/enumerable-each-vs-for-loops-in-ruby

更加清楚:http://www.ruby-forum.com/topic/179264#784884

+0

'loop1'和'loop2'未定义。 – 2014-05-03 17:20:33

+0

答案更新!谢谢@DarekNędza – 2014-05-03 19:47:25

0

千万不要使用for它可能会导致错误。

区别是微妙的,但可能会导致巨大的错误!

不要被愚弄,这不是关于惯用代码或样式问题。这是避免生产代码中几乎无法追踪的错误的问题。 Ruby的for的实现有一个严重的缺陷,不应该使用。始终使用each循环,永远不会使用for循环。

这里是for引入了一个错误的例子,

class Library 
    def initialize 
    @ary = [] 
    end 
    def method_with_block(&block) 
    @ary << block 
    end 
    def method_that_uses_these_blocks 
    @ary.map(&:call) 
    end 
end 

lib = Library.new 

for n in %w{foo bar quz} 
    lib.method_with_block { n } 
end 

puts lib.method_that_uses_these_blocks 

打印

quz 
quz 
quz 

使用%w{foo bar quz}.each { |n| ... }打印

foo 
bar 
quz 

为什么?

for循环中,变量n定义了一次,然后该定义用于所有迭代。因此,每个块指代在循环结束时具有值quz的相同n。错误!

在一个each循环新鲜变量n被定义为每次迭代,例如可变n上述定义三个独立倍。因此,每个块都指代具有正确值的单独的n

+0

你的意思是“方法”,而不是“功能”。 – 2016-12-23 23:40:16

+0

@ericduminil好抓,太多polyglot,哈哈。 – akuhn 2016-12-23 23:44:09