Ruby: for循环和each循环有什么区别?

5

可能是重复问题:
在Ruby中for和each有什么区别?

假设我们有一个数组,如下所示

sites = %w[stackoverflow stackexchange serverfault]

for item in sitessites.each do |item|有什么区别?

for x in sites do
  puts x
end

并且

sites.each do |x|
  puts x
end

在我看来,它们似乎做完全相同的事情,而且for循环的语法对我来说更清晰。它们有区别吗?在什么情况下这会成为一个大问题?


我检查了类似的东西,但是没有看到它。 - eckza
4个回答

27

关于作用域方面有一个微妙的区别,但我建议深入理解,因为它揭示了Ruby的一些重要方面。

for是一种语法结构,与if有些相似。无论您在for块中定义了什么,都将在for之后保持定义:

sites = %w[stackoverflow stackexchange serverfault]
#=> ["stackoverflow", "stackexchange", "serverfault"]

for x in sites do
  puts x
end
stackoverflow
stackexchange
serverfault
#=> ["stackoverflow", "stackexchange", "serverfault"]
x
#=> "serverfault"

另一方面,each是一个接收块的方法。块引入了新的词法作用域,因此,在其中引入的任何变量在方法完成后都不会存在:

sites.each do |y|
  puts y
end
stackoverflow
stackexchange
serverfault
#=> ["stackoverflow", "stackexchange", "serverfault"]
y
NameError: undefined local variable or method `y' for #<Object:0x855f28 @hhh="hello">
    from (irb):9
    from /usr/bin/irb:12:in `<main>'

我建议完全忘记使用for,因为在Ruby中使用each来遍历可枚举对象是惯用法。它还更好地尊重函数式编程的范例,减少了副作用的可能性。


非常好的回答 - 解释非常清晰和详细。非常感谢! - eckza
非常有趣。我以为它们是一样的! :) - fl00r
这是在技术面试中提出的问题,非常有用的信息! - fatfrog

8

sites.each在块内部限定x的范围,而for会重复使用在块外声明的x。因此一般最好使用each,它可以在大量代码中最小化副作用。


4

CBZ的回答是正确的,但不完整,因为1.8.X和1.9.X之间存在行为差异:

1.9.2 IRB:

ruby-1.9.2-p180 :001 > x = [1,2,3,4,5]
 => [1, 2, 3, 4, 5] 
ruby-1.9.2-p180 :002 > y = ["a","b"]
 => ["a", "b"] 
ruby-1.9.2-p180 :003 > x.each do |y|
ruby-1.9.2-p180 :004 >     p y
ruby-1.9.2-p180 :005?>   end
1
2
3
4
5
 => [1, 2, 3, 4, 5] 
ruby-1.9.2-p180 :006 > y
 => ["a", "b"] 

1.8.7 IRB:

ree-1.8.7-2011.03 :001 > x = [1,2,3,4,5]
 => [1, 2, 3, 4, 5] 
ree-1.8.7-2011.03 :002 > y = ["a","b"]
 => ["a", "b"] 
ree-1.8.7-2011.03 :003 > x.each do |y|
ree-1.8.7-2011.03 :004 >     p y
ree-1.8.7-2011.03 :005?>   end
1
2
3
4
5
 => [1, 2, 3, 4, 5] 
ree-1.8.7-2011.03 :006 > y
 => 5 

谢谢澄清。就我所知,我正在使用1.9.2版本。 - eckza

-1

CBZ的回答是正确的。为了阐述这一点,请看以下例子:

ruby-1.9.2-p180 :001 > a = %w{ blah lah kah }
 => ["blah", "lah", "kah"] 
ruby-1.9.2-p180 :002 > x = 1
 => 1 
ruby-1.9.2-p180 :003 > for x in a do
ruby-1.9.2-p180 :004 >     puts x
ruby-1.9.2-p180 :005?>   end
blah
lah
kah
 => ["blah", "lah", "kah"] 
ruby-1.9.2-p180 :006 > x
 => "kah" 
ruby-1.9.2-p180 :007 > x=1
 => 1 
ruby-1.9.2-p180 :008 > a.each do |x|
ruby-1.9.2-p180 :009 >     puts x
ruby-1.9.2-p180 :010?>   end
blah
lah
kah
 => ["blah", "lah", "kah"] 
ruby-1.9.2-p180 :011 > x
 => 1 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接