Tenho dificuldade em entender quando e por que o valor mantido por um Scalar
contêiner enviado é afetado após o envio. Tentarei ilustrar a questão que encontrei em um contexto mais complicado em dois exemplos estilizados.
* Exemplo 1 * No primeiro exemplo, um escalar $i
é empurrado para uma matriz @b
como parte de a List
. Após o envio, o valor mantido pelo escalar é explicitamente atualizado nas iterações posteriores do loop for usando a $i++
instrução Essas atualizações afetam o valor da matriz @b
: no final do loop @b[0;0]
for , é igual a 3
, e não mais 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;
Exemplo de saída 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
* Exemplo 2 * No segundo exemplo, o escalar $i
é a variável de loop. Mesmo que $i
é atualizado depois de ter sido empurrado (agora implicitamente, em vez de explicitamente), o valor de $i
em conjunto @c
se não
mudar após o impulso; ou seja, após o loop for 2
, ainda é , não 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;;
Exemplo de saída 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
Pergunta: Porque é que $i
em @b
no exemplo 1 atualizado após o impulso, enquanto $i
em @c
no exemplo 2 não é?
edit : Após o comentário de @ timotimo, incluí a saída de .WHERE
nos exemplos. Isso mostra a identidade escalar (WHICH / logic) de $i
permanece a mesma, enquanto seu endereço de memória é alterado pelas várias iterações de loop. Mas não explica por que, no exemplo 2, o escalar empurrado permanece vinculado à mesma identidade WHICH em combinação com um endereço antigo ("448).
fonte
.WHERE
vez de,.WHICH
poderá ver que o escalar é realmente um objeto diferente a cada vez no loop. Isso acontece porque os blocos pontiagudos são "chamados" e a assinatura é "vinculada" a cada chamada.Respostas:
Um valor escalar é apenas um contêiner. Você pode pensar neles como uma espécie de ponteiro inteligente, e não como um valor primitivo.
Se você fizer uma tarefa
você está alterando o valor das escalares, o contêiner permanece o mesmo.
Considerar
e
Ambos funcionam como esperado. Mas: nos dois casos, a coisa na lista não é mais mutável, porque não há contêiner.
portanto, morrerá. Então, basta usar a variável loop, certo?
Não.
mesmo se iterarmos sobre uma lista de coisas mutáveis.
Portanto, não há aliasing aqui, em vez disso, a variável loop é sempre o mesmo contêiner e obtém valores atribuídos provenientes dos outros contêineres.
Nós podemos fazer isso embora.
Uma maneira de tornar "a coisa" mutável é usar uma variável intermediária.
funciona bem. Ou mais curto e mais no contexto original
Veja também:
https://perl6advent.wordpress.com/2017/12/02/#theoneandonly https://docs.perl6.org/language/containers
fonte
($x,1)
, você também pode fazer[$x,1]
o que iria criar um novo contêiner (também para1
, BTW)Int
objeto ->Int
é substituído no loop for - - o container aponta para novoInt
), mas o segundo não.Depois de brincar e pensar na minha pergunta acima por algum tempo, aposto uma resposta ... É pura conjectura da minha parte, então fique à vontade para dizer que não faz sentido se é e se você sabe, porque...
No primeiro exemplo,
$i
é definido fora do escopo lexical do loop for. Conseqüentemente,$i
existe independentemente do loop e de suas iterações. Quando$i
é referenciado de dentro do loop, há apenas um$i
que pode ser afetado. É isso$i
que é empurrado para dentro@b
, e seu conteúdo é modificado posteriormente no loop.No segundo exemplo,
$i
é definido dentro do escopo lexical do loop for. Como o @timotimo apontou, o bloco apontado é chamado para cada iteração, como uma sub-rotina;$i
é, portanto, declarado recentemente para cada iteração e com escopo definido para o respectivo bloco. Quando$i
é referenciada dentro do loop, a referência é específica ao bloco de iteração$i
, que normalmente deixaria de existir quando a respectiva iteração de loop terminasse. Mas como em algum momento$i
é enviado para@c
, a referência ao$i
valor de retenção específico da iteração de bloco2
não pode ser excluída pelo coletor de lixo após o término da iteração. Ele permanecerá na existência ..., mas ainda será diferente das$i
iterações posteriores.fonte