sintaxis - Ruby: ¿Cuál es la diferencia entre un bucle for y cada bucle?
iteration ruby (4)
Posible duplicado:
para vs cada uno en Ruby
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 bucle for
es más clara para mí. ¿Hay una diferencia? ¿En qué situaciones sería esto un gran problema?
Hay una diferencia sutil con respecto al alcance, pero recomendaría entenderlo bien, ya que revela algunos de los aspectos importantes de Ruby.
for
es una construcción de sintaxis, algo similar a if
. Independientemente de lo que defina en el bloque, también se definirá después for
:
sites = %w[ stackexchange serverfault]
#=> ["", "stackexchange", "serverfault"]
for x in sites do
puts x
end
stackexchange
serverfault
#=> ["", "stackexchange", "serverfault"]
x
#=> "serverfault"
Por otro lado, each
es un método que recibe un bloque. Block introduce un nuevo ámbito léxico, por lo que cualquier variable que introduzca en él, no estará allí después de que el método finalice:
sites.each do |y|
puts y
end
stackexchange
serverfault
#=> ["", "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>''
Recomendaría olvidar for
completo, ya que 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.
La respuesta CBZ es correcta pero incompleta ya que hay una diferencia en el 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
La respuesta CBZ es correcta. Para ilustrar esto, mira 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
sites.each
alcance x
dentro del bloque, mientras que for
reutilizará x
si se declara fuera del bloque. En general, es mejor usar each
, minimiza los efectos secundarios sobre grandes cuerpos de código.