我有一个关于Ruby循环的问题。这两种遍历集合的方法有区别吗?

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

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

只是想知道这些是否完全相同,或者是否可能有细微的差异(可能在@collection为nil时)。


当前回答

我只是想特别说明一下Ruby中的for in循环。它看起来像是一个类似于其他语言的构造,但实际上它是一个像Ruby中其他循环构造一样的表达式。事实上,for In与Enumerable对象的作用就像each迭代器一样。

传递给for in的集合可以是任何具有each迭代器方法的对象。数组和散列定义了每个方法,许多其他Ruby对象也是如此。for/in循环调用指定对象的每个方法。当迭代器生成值时,for循环将每个值(或每一组值)赋给指定的变量(或多个变量),然后执行代码体。

这是一个愚蠢的例子,但说明了for in循环适用于具有each方法的ANY对象,就像each迭代器一样:

class Apple
  TYPES = %w(red green yellow)
  def each
    yield TYPES.pop until TYPES.empty?
  end
end

a = Apple.new
for i in a do
  puts i
end
yellow
green
red
=> nil

现在是each迭代器:

a = Apple.new
a.each do |i|
  puts i
end
yellow
green
red
=> nil

As you can see, both are responding to the each method which yields values back to the block. As everyone here stated, it is definitely preferable to use the each iterator over the for in loop. I just wanted to drive home the point that there is nothing magical about the for in loop. It is an expression that invokes the each method of a collection and then passes it to its block of code. Hence, it is a very rare case you would need to use for in. Use the each iterator almost always (with the added benefit of block scope).

其他回答

我只是想特别说明一下Ruby中的for in循环。它看起来像是一个类似于其他语言的构造,但实际上它是一个像Ruby中其他循环构造一样的表达式。事实上,for In与Enumerable对象的作用就像each迭代器一样。

传递给for in的集合可以是任何具有each迭代器方法的对象。数组和散列定义了每个方法,许多其他Ruby对象也是如此。for/in循环调用指定对象的每个方法。当迭代器生成值时,for循环将每个值(或每一组值)赋给指定的变量(或多个变量),然后执行代码体。

这是一个愚蠢的例子,但说明了for in循环适用于具有each方法的ANY对象,就像each迭代器一样:

class Apple
  TYPES = %w(red green yellow)
  def each
    yield TYPES.pop until TYPES.empty?
  end
end

a = Apple.new
for i in a do
  puts i
end
yellow
green
red
=> nil

现在是each迭代器:

a = Apple.new
a.each do |i|
  puts i
end
yellow
green
red
=> nil

As you can see, both are responding to the each method which yields values back to the block. As everyone here stated, it is definitely preferable to use the each iterator over the for in loop. I just wanted to drive home the point that there is nothing magical about the for in loop. It is an expression that invokes the each method of a collection and then passes it to its block of code. Hence, it is a very rare case you would need to use for in. Use the each iterator almost always (with the added benefit of block scope).

这是唯一的区别:

每一个:

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

for:

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

对于for循环,迭代器变量在块完成后仍然存在。对于每个循环,它都不会,除非它在循环开始之前已经定义为局部变量。

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

当@collection为nil时,两个循环都会抛出异常:

异常:main:Object未定义的局部变量或方法“@collection”

(1..4).each { |i| 


  a = 9 if i==3

  puts a 


}
#nil
#nil
#9
#nil

for i in 1..4

  a = 9 if i==3

  puts a

end
#nil
#nil
#9
#9

在for循环中,局部变量在每次循环后仍然有效。在“each”循环中,局部变量在每次循环后都会刷新。

请参阅“For循环的弊端”以获得更好的解释(考虑到变量作用域,有一个小区别)。

使用这两种都被认为是Ruby更习惯的用法。

第一个例子,

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

更习惯用语。虽然Ruby支持for和While等循环结构,但块语法通常是首选。

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