“Para” vs “cada uno” en Ruby

Acabo de tener una pregunta rápida con respecto a los bucles en Ruby. ¿Hay 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 estos son exactamente iguales o si tal vez hay una diferencia sutil (posiblemente cuando @collection es 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 bucle for , la variable del iterador sigue viva después de que el bloque está listo. Con each bucle, no es así, a menos que ya se haya definido como una variable local antes de que se inicie el bucle.

Aparte de eso, for es solo azúcar de syntax para each método.

Cuando @collection es nil ambos loops arrojan una excepción:

Excepción: variable local indefinida o método `@collection ‘para main: Object

Consulte ” The Evils of the For Loop ” para obtener una buena explicación (hay una pequeña diferencia considerando el scope variable).

El uso de 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 de bucle como for y while , generalmente se prefiere la syntax de bloque.

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

Una más diferente …

 number = ["one", "two", "three"] => ["one", "two", "three"] loop1 = [] loop2 = [] number.each do |c| loop1 < < Proc.new { puts c } end => ["one", "two", "three"] for c in number loop2 < < Proc.new { puts c } end => ["one", "two", "three"] loop1[1].call two => nil loop2[1].call three => nil 

fuente: http://paulphilippov.com/articles/enumerable-each-vs-for-loops-in-ruby

para más claro: http://www.ruby-forum.com/topic/179264#784884

Parece que no hay diferencia, for each debajo.

 $ irb >> for x in nil >> puts x >> end NoMethodError: undefined method `each' for nil:NilClass from (irb):1 >> nil.each {|x| puts x} NoMethodError: undefined method `each' for nil:NilClass from (irb):4 

Como dice Bayard, cada uno es más idiomático. Oculta más de usted y no requiere funciones especiales de idioma. Comentario de Telémaco

for .. in .. establece el iterador fuera del scope del ciclo, por lo

 for a in [1,2] puts a end 

deja a definido después de que el ciclo haya terminado. Donde como each no lo hace. Cuál es otra razón a favor de usar each , porque la variable de la temperatura vive un período más corto.

Nunca lo use, puede causar errores.

¡La diferencia es sutil pero puede causar errores tremendos!

No se deje engañar, no se trata de un código idiomático o de problemas de estilo. Se trata de evitar errores casi imposibles de detectar en el código de producción. La implementación de Ruby for tiene un defecto serio y no debería usarse. Siempre use each bucle, nunca lo use for bucle.

Aquí hay un ejemplo donde for introducir 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 

Usar %w{foo bar quz}.each { |n| ... } %w{foo bar quz}.each { |n| ... } impresiones

 foo bar quz 

¿Por qué?

En un bucle for la variable n se define una sola vez y luego esa única definición se usa para todas las iteraciones. Por lo tanto, cada bloque se refiere a la misma n que tiene un valor de quz en el momento en que termina el ciclo. ¡Error!

En each bucle se define una nueva variable n para cada iteración, por ejemplo, arriba de la variable n se define tres veces por separado. Por lo tanto, cada bloque se refiere a una n separada con los valores correctos.

Hasta donde yo sé, usar bloques en lugar de estructuras de control en lenguaje es más idiomático.