2010-07-20 119 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