2011-04-15 2 views
5

Можно создать дубликат:
for vs each in RubyRuby: В чем разница между циклами for и каждым циклом?

Давайте предположим, что у нас есть массив, как

sites = %w[stackoverflow stackexchange serverfault]

В чем разница между

for x in sites do 
    puts x 
end 

и

sites.each do |x| 
    puts x 
end 

?

Они, кажется, делают то же самое, для меня, и синтаксис цикла for яснее для меня. Есть ли разница? В каких ситуациях это будет иметь большое значение?

+0

Я проверил что-то подобное, но я этого не видел. – eckza

ответ

26

Существует тонкое различие в отношении определения объема, но я рекомендовал бы понять это хорошо, как это показывает некоторые из важных аспектов 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 полностью, так как с помощью each идиоматичен в Ruby, для обхода перечислимых. Он также лучше рассматривает парадигму функционального программирования, уменьшая шансы на побочные эффекты.

+0

Отличный ответ - очень четкое и полное объяснение. Большое спасибо! – eckza

+0

+1 Отличный ответ. – Krule

+0

Очень интересно.Я думал, что они такие же! :) – fl00r

8

sites.each области x внутри блока, тогда как for будет повторно использовать x, если объявлено вне блока. В общем, лучше использовать each, он минимизирует побочные эффекты по большим телам кода.

-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 
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 
+0

Спасибо за разъяснение. Для чего это стоит, я использую 1.9.2. – eckza

Смежные вопросы