Ruby: What is the difference between a for loop and an each loop? [duplicate]

吃可爱长大的小学妹 提交于 2019-12-04 08:52:36

There is a subtle difference regarding scoping, but I would recommend understanding it well as it reveals some of important aspects of Ruby.

for is a syntax construct, somewhat similar to if. Whatever you define in for block, will remain defined after for as well:

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

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

On the other hand, each is a method which receives a block. Block introduces new lexical scope, so whatever variable you introduce in it, will not be there after the method finishes:

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>'

I would recommend forgetting about for completely, as using each is idiomatic in Ruby for traversing enumerables. It also recspects the paradigm of functional programming better, by decreasing chances of side-effects.

cbz

sites.each scopes x inside the block, whereas for will reuse x if declared outside the block. In general it's better therefore to use each, it minimizes side effects over large bodies of code.

CBZ answer is correct but incomplete since there is a difference in behavior between 1.8.X and 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 

CBZ answer is correct. To illustrate this, see this example:

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 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!