2011-04-15 17 views
5

Duplicar posible:
for vs each in RubyRuby: ¿Cuál es la diferencia entre un bucle for y cada bucle?

Digamos que tenemos una matriz, como

sites = %w[stackoverflow stackexchange serverfault]

¿Cuál es la diferencia entre

for x in sites do 
    puts x 
end 

y

sites.each do |x| 
    puts x 
end 

?

Parecen hacer exactamente lo mismo, para mí, y la sintaxis del lazo for es más clara para mí. ¿Hay una diferencia? ¿En qué situaciones sería esto un gran problema?

+0

Comprobé algo así, pero no lo vi. – eckza

Respuesta

26

Hay una sutil diferencia respecto de alcance, pero yo recomendaría entenderlo así, ya que revela algunos de los aspectos importantes de Ruby.

for es una construcción de sintaxis, algo similar a if. Lo que defina en for bloque, quedará definido después for así:

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

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

Por otro lado, each es un métodoque recibe un bloque. Bloquear presenta nuevo ámbito léxico, por lo que cualquier variable que se introduce en ella, no estará allí después de que finalice el método:

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

lo recomiendo olvidarse de for por completo, como el uso de each es idiomático en Ruby para atravesar enumerables. También reconoce mejor el paradigma de la programación funcional al disminuir las posibilidades de efectos secundarios.

+0

Gran respuesta: explicación muy clara y completa. ¡Muchas gracias! – eckza

+0

+1 Gran respuesta. – Krule

+0

Muy interesante.¡Pensé que son lo mismo! :) – fl00r

8

sites.each Scopes x dentro del bloque, mientras que for reutilizará x si declarado fuera del bloque. En general, es mejor utilizar each, minimiza los efectos secundarios en grandes cantidades de código.

-1

CBZ la respuesta es correcta. Para ilustrar esto, vea este ejemplo:

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 respuesta es correcta pero incompleta ya que existe una diferencia de comportamiento entre 1.8.x y 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

Gracias por aclarar. Por lo que vale, estoy usando 1.9.2. – eckza

Cuestiones relacionadas