Tengo dificultades para comprender cuándo y por qué el valor que tiene un Scalar
contenedor enviado se ve afectado después del envío. Trataré de ilustrar el problema que encontré en un contexto más complicado en dos ejemplos estilizados.
* Ejemplo 1 * En el primer ejemplo, un escalar $i
se inserta en una matriz @b
como parte de a List
. Después de la inserción, el valor mantenido por el escalar se actualiza explícitamente en iteraciones posteriores del bucle for utilizando la $i++
instrucción. Estas actualizaciones tienen un efecto en el valor de la matriz @b
: al final del ciclo for, @b[0;0]
es igual a 3
, y ya no lo es 2
.
my @b;
my $i=0;
for 1..3 -> $x {
$i++;
say 'Loose var $i: ', $i.VAR.WHICH, " ", $i.VAR.WHERE;
if $x == 2 {
@b.push(($i,1));
say 'Pushed $i : ', @b[0;0].VAR.WHICH, " ", @b[0;0].VAR.WHERE;
}
}
say "Post for-loop";
say "Array : ", @b;
say 'Pushed $i : ', @b[0;0].VAR.WHICH, " ", @b[0;0].VAR.WHERE;
Ejemplo de salida 1:
Loose var $i: Scalar|94884317665520 139900170768608
Loose var $i: Scalar|94884317665520 139900170768648
Pushed $i : Scalar|94884317665520 139900170768648
Loose var $i: Scalar|94884317665520 139900170768688
Post for-loop
Array : [(3 1)]
Pushed $i : Scalar|94884317665520 139900170768688
* Ejemplo 2 * En el segundo ejemplo, el escalar $i
es la variable de bucle. A pesar de que $i
se actualiza después de que ha sido empujado (ahora implícita más que explícitamente), el valor de $i
en la matriz @c
no no
cambia después de pulsar; es decir, después del ciclo for, todavía está 2
, no 3
.
my @c;
for 1..3 -> $i {
say 'Loose var $i: ', $i.VAR.WHICH, " ", $i.VAR.WHERE;
if $i == 2 {
@c.push(($i,1));
say 'Pushed $i : ', @c[0;0].VAR.WHICH, " ", @c[0;0].VAR.WHERE;
}
}
say "Post for-loop";
say "Array : ", @c;
say 'Pushed $i : ', @c[0;0].VAR.WHICH, " ", @c[0;0].VAR.WHERE;;
Ejemplo de salida 2:
Loose var $i: Scalar|94289037186864 139683885277408
Loose var $i: Scalar|94289037186864 139683885277448
Pushed $i : Scalar|94289037186864 139683885277448
Loose var $i: Scalar|94289037186864 139683885277488
Post for-loop
Array : [(2 1)]
Pushed $i : Scalar|94289037186864 139683885277448
Pregunta: ¿Por qué es $i
en @b
en el ejemplo 1 actualizado después de que el empuje, mientras que $i
en @c
en el ejemplo 2 no es?
editar : Siguiendo el comentario de @ timotimo, incluí la salida de .WHERE
en los ejemplos. Esto muestra la identidad escalar (QUE / lógica) de $i
permanece igual, mientras que su dirección de memoria cambia a través de las diversas iteraciones de bucle. Pero no explica por qué en el ejemplo 2 el escalar empujado permanece atado a la misma identidad QUE en combinación con una dirección anterior ("448).
fuente
.WHERE
lugar de.WHICH
, puede ver que el escalar es en realidad un objeto diferente cada vez alrededor del bucle. Eso sucede porque los bloques puntiagudos se "llaman" y la firma se "vincula" en cada llamada.Respuestas:
Un valor escalar es solo un contenedor. Puede pensar en ellos como una especie de puntero inteligente, en lugar de un valor primitivo.
Si haces una tarea
Si está cambiando el valor de los escalares, el contenedor permanece igual.
Considerar
y
Ambos funcionan como se esperaba. Pero: en ambos casos, la cosa en la lista ya no es mutable, porque no hay contenedor.
Por lo tanto, morirá. Entonces, solo use la variable de bucle, ¿verdad?
No.
incluso si iteramos sobre una lista de cosas mutables.
Por lo tanto, no hay alias aquí, en su lugar, la variable de bucle siempre es el mismo contenedor y obtiene valores asignados que provienen de los otros contenedores.
Sin embargo, podemos hacer esto.
Una manera de hacer que "la cosa" sea mutable es usar una variable intermedia.
funciona bien. O más corto y más en el contexto original
Ver también:
https://perl6advent.wordpress.com/2017/12/02/#theoneandonly https://docs.perl6.org/language/containers
fuente
($x,1)
, también podría hacer[$x,1]
lo que crearía un nuevo contenedor (también para1
, por cierto)Int
objeto ->Int
se reemplaza por bucle -> el contenedor apunta a nuevoInt
), pero el segundo no.Después de jugar y pensar en mi pregunta anterior por un tiempo, apostaré una respuesta ... Es pura conjetura de mi parte, así que siéntase libre de decir que no tiene sentido si es así, y si usted sabe, por qué...
En el primer ejemplo,
$i
se define fuera del alcance léxico del bucle for. En consecuencia,$i
existe independientemente del bucle y sus iteraciones. Cuando$i
se hace referencia desde el interior del bucle, solo hay uno$i
que puede verse afectado. Es esto en lo$i
que se empuja@b
, y luego se modifica su contenido en el ciclo.En el segundo ejemplo,
$i
se define dentro del alcance léxico del bucle for. Como señaló @timotimo, se llama al bloque puntiagudo para cada iteración, como una subrutina;$i
por lo tanto, se declara recientemente para cada iteración y se limita al bloque respectivo. Cuando$i
se hace referencia dentro del bucle, la referencia es a la iteración de bloque específica$i
, que normalmente dejaría de existir cuando finaliza la iteración del bucle respectivo. Pero debido a que en algún momento$i
se empuja@c
, el recolector de basura no puede eliminar la referencia al$i
valor de retención específico de la iteración de bloque2
después de la terminación de la iteración. Permanecerá en existencia ..., pero seguirá siendo diferente de las$i
iteraciones posteriores.fuente