Asigno el valor "1" a las variables x e y fuera del bloque, y luego hago referencia a la variable x del mismo nombre fuera del bloque en un bloque, por lo que x es ambos 1.
A continuación, asigno el valor de x a y en el bloque. En teoría, y también debería ser 1, pero el resultado más confiable es x = 1, y = 3 .
Por favor dime porque.
x = 1 y = 1 ary = [1, 2, 3] ary.each do |x| y = x end p [x, y]La fuente de confusión aquí es el llamado ensombrecimiento. Aquí tiene dos variables locales llamadas x , pero solo una llamada y . La segunda variable x está sombreando a la primera, lo que significa que cualquier intento de acceder o asignar a la primera variable está condenado al fracaso.
Cuando haces ary.each do |x| , está creando una nueva variable, que no tiene nada (excepto el nombre) que ver con la variable x que ha creado en el ámbito externo.
y , por otro lado, no está sombreado y el enlace del bucle está accediendo (y asignando) a la variable definida en el ámbito principal. Desafortunadamente, no hay forma (al menos que yo sepa) de creación explícita de variables locales como var / let / const en javascript.
En resumen, su código se ejecuta de la siguiente manera:
x = 1 y = 1 ary = [1, 2, 3] ary.each do |x2| y = x2 end p [x, y] Entonces, de hecho, la asignación a y funciona como se esperaba. Le asignas el valor de 1 antes del bloque, y luego asignas 3 veces más dentro del bloque. La última asignación es y=3 , así que ese es su valor final.
CUIDADO, EL HACK:
Bueno, en realidad hay una forma de forzar la creación de variables locales, y es agregar un argumento de rendimiento adicional a cada bloque. Esto nunca debe hacerse en el código real , y solo lo presento para que esté completo. En realidad, debe evitar cualquier sombreado variable siempre que sea posible.
x = y = 1 ary = [2,3,4] ary.each do |x, y| # this creates new local variables x and y, y is always set to nil for each iteration. y = x # y here is a shadowing variable, not the y of the parent scope puts [x,y].inspect end puts [x,y].inspect # OUTPUTS: [2, 2] [3, 3] [4, 4] [1, 1]Los parámetros de bloque (las cosas entre las tuberías como |x,y| ) son locales para el bloque. Pero las variables preexistentes no lo son.
total = 0 [1,5].each{|n| total += n} #works because total starts out as 0 puts total # => 6 Si desea un total local de bloque, siga los parámetros con un punto y coma y una lista de variables separadas por comas
total = 0 [1,5].each{|n; total, _unused| total += n} #Error because total is nil puts totalPorque estás redefiniendo x en el ámbito del bloque. ary.each do |x| Haz esto.