Ruby: una breve explicación sobre each / for y su scope – un secreto que deberías saber


learningRuby En el curso de Rails que estoy dando, junto con Gaby en la plataforma Neurodidactika de ASPgems, he visto necesario comentar algunas cosas interesantes de sobre for y sobre each. Son dos bucles (loops) que cuando has trabajado con otros lenguajes de programación puedes pensar que puedes utilizarlo indistintamente, pero te voy a enseñar algunas cosas que deberías saber antes de tomar una decisión de utilizar for o each.

Todo parte desde el punto en que ves en la vista index de products, el código para poder ver todos los productos. Pare ello, necesitamos iterar sobre nuestra variable de instancia con un bucle each: @products.each do |product| y pensar que también lo podemos hacer con un for sin problemas y es cierto, ya que utilizamos una variable de instancia @products. Pero veamos las diferencias que deberías tener presente.

En primer lugar voy a hablarte de for. Cuando trabajamos con un for, lo primero que tienes que saber es que la variable que declaramos para utilizar un for, es necesario saber dónde comienza y cuándo termina. es decir, el scope de dicha variable.

Primero declaramos la variable list, iteramos y finalmente visualizamos. Veamos un ejemplo:

list = %w{ adolfo luis alberto carlossanchezperez }
for engine in list
  # do something with engine that you like it
end
puts engine
# carlossanchezperez

Como puedes comprobar cuando trabajamos el array list dentro del for vamos a poder hacer uso de ella y una vez finalizado el bloque del for vemos que nos dice engine, tenemos como resultado “carlossanchezperez”, ¿qué curioso verdad? bueno espera déjame que sigamos para que lo entiendas. Si esto mismo lo hacemos con un each, veamos que resultado obtenemos:

list = %w{ adolfo luis alberto carlossanchezperez }

list.each do |engine|

  # do something with engine
end
puts engine
# NameError: undefined local variable or method ‘engine’
El resultado, cuando lo vi por primera vez, me dejo un poco confuso, pero en cierta forma entendía que el scope de la variable definida engine en el primer caso del for  está fuera del bloque for, ya que la define antes y en el caso de each la variable engine queda dentro del bloque each, por lo que cuando preguntamos por ella fuera del ámbito del each, nos dice que no la conoce. Bueno, podríamos quedarnos aquí y tenemos un explicación del ambito de la variable. pero creo necesario ir un poco más lejos. Podemos pensar que podríamos evitar que el scope nos impida que esto nos pase y le damos protagonismo a un lambda o un proc o un Proc.new¿Cómo podemos hacerlo? Veamos un primer ejemplo con for:
results = [ ]
for i in 1..3
     results << lambda { i }
end
puts results.map { |l| l.call }

En el segundo caso veamos cómo sería con un each:

results = [ ]
(1..3).each do |i|
    results << lambda { i }
end
puts results.map { |l| l.call }
El resultado de ambos es que tenemos que, el ámbito de la variable ya no nos arroja un error como en los primeros ejemplos, en ambos casos obtenemos resultados distintos, pero tenemos un resultado que le vamos a dar una explicación final. En el caso del for obtenemos tres 3 y en el caso del each obtenemos 1, 2 y 3.
Ahora ya podemos dar una explicación lógica, en los primeros ejemplos, el  ámbito de la variable en el for es, que declara la variable antes del bloque del for y trabaja el bloque con el código que sea y cuando termina tenemos la misma variable declarada en el inicio. Para el caso del each tenemos una variable declarada en cada iteracción del bloque each, por eso al terminar tenemos como resultado 1, 2 y 3. Ahora ya tienes información para saber cuándo utilizar cada una de ellas.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s