sintaxis - "Para" vs "cada uno" en Ruby
ruby map (7)
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).
Consulte " The Evils of the For Loop " para obtener una buena explicación (hay una pequeña diferencia considerando el alcance variable).
El uso de each
se considera un uso más idiomático de Ruby.
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 sintaxis 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
Hasta donde yo sé, usar bloques en lugar de estructuras de control en lenguaje es más idiomático.
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.
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 alcance 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.
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 sintaxis 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