"para" frente a "cada uno" en Ruby
Acabo de tener una pregunta rápida sobre los bucles en Ruby. ¿Existe alguna diferencia entre estas dos formas de iterar a través de una colección?
# way 1
@collection.each do |item|
# do whatever
end
# way 2
for item in @collection
# do whatever
end
Solo me pregunto si son exactamente iguales o si tal vez haya una diferencia sutil (posiblemente cuando @collection
sea nulo).
Esta es la única diferencia:
cada:
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
para:
irb> for x in [1,2,3]; end
=> [1, 2, 3]
irb> x
=> 3
Con el for
bucle, la variable iteradora aún vive una vez finalizado el bloque. Con el each
bucle, no es así, a menos que ya estuviera definido como una variable local antes de que comenzara el bucle.
Aparte de eso, for
es solo azúcar de sintaxis para el each
método.
@collection
¿ Cuándo nil
ambos bucles arrojan una excepción?
Excepción: variable local no definida o método `@collection' para principal:Objeto
Consulte " Los males del bucle For " para obtener una buena explicación (hay una pequeña diferencia al considerar el alcance variable).
El uso each
se considera un uso más idiomático de Ruby.
Tu primer ejemplo,
@collection.each do |item|
# do whatever
end
es más idiomático . Si bien Ruby admite construcciones en bucle como for
y while
, generalmente se prefiere la sintaxis de bloque.
Otra diferencia sutil es que cualquier variable que declare dentro de un for
bucle estará disponible fuera del bucle, mientras que aquellas dentro de un bloque iterador son efectivamente privadas.
Nunca usarlo for
puede causar errores casi imposibles de rastrear.
No se deje engañar, no se trata de código idiomático o cuestiones de estilo. La implementación de Ruby for
tiene un defecto grave y no debe utilizarse.
Aquí hay un ejemplo donde for
se introduce un error,
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
Huellas dactilares
quz
quz
quz
Usando %w{foo bar quz}.each { |n| ... }
impresiones
foo
bar
quz
¿Por qué?
En un for
bucle, la variable n
se define una sola vez y luego esa definición se usa para todas las iteraciones. Por lo tanto, cada bloque se refiere al mismo n
que tiene un valor de quz
cuando finaliza el ciclo. ¡Bicho!
En un each
bucle, se define una nueva variable n
para cada iteración; por ejemplo, arriba, la variable n
se define tres veces por separado. Por lo tanto, cada bloque se refiere a uno separado n
con los valores correctos.