"para" frente a "cada uno" en Ruby

Resuelto mportiz08 asked hace 14 años • 10 respuestas

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 @collectionsea nulo).

mportiz08 avatar Jul 21 '10 04:07 mportiz08
Aceptado

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 forbucle, la variable iteradora aún vive una vez finalizado el bloque. Con el eachbucle, no es así, a menos que ya estuviera definido como una variable local antes de que comenzara el bucle.

Aparte de eso, fores solo azúcar de sintaxis para el eachmétodo.

@collection¿ Cuándo nilambos bucles arrojan una excepción?

Excepción: variable local no definida o método `@collection' para principal:Objeto

Paige Ruten avatar Jul 20 '2010 21:07 Paige Ruten

Consulte " Los males del bucle For " para obtener una buena explicación (hay una pequeña diferencia al considerar el alcance variable).

El uso eachse considera un uso más idiomático de Ruby.

ChristopheD avatar Jul 20 '2010 21:07 ChristopheD

Tu primer ejemplo,

@collection.each do |item|
  # do whatever
end

es más idiomático . Si bien Ruby admite construcciones en bucle como fory while, generalmente se prefiere la sintaxis de bloque.

Otra diferencia sutil es que cualquier variable que declare dentro de un forbucle estará disponible fuera del bucle, mientras que aquellas dentro de un bloque iterador son efectivamente privadas.

Bayard Randel avatar Jul 20 '2010 21:07 Bayard Randel

Nunca usarlo forpuede 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 fortiene un defecto grave y no debe utilizarse.

Aquí hay un ejemplo donde forse 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 forbucle, la variable nse define una sola vez y luego esa definición se usa para todas las iteraciones. Por lo tanto, cada bloque se refiere al mismo nque tiene un valor de quzcuando finaliza el ciclo. ¡Bicho!

En un eachbucle, se define una nueva variable npara cada iteración; por ejemplo, arriba, la variable nse define tres veces por separado. Por lo tanto, cada bloque se refiere a uno separado ncon los valores correctos.

akuhn avatar Dec 23 '2016 22:12 akuhn