Mam trudności ze zrozumieniem, kiedy i dlaczego wartość trzymana przez przepchnięty Scalar
pojemnik ma wpływ po wypchnięciu. Spróbuję zilustrować problem, na który wpadłem w bardziej skomplikowanym kontekście, w dwóch stylizowanych przykładach.
* Przykład 1 * W pierwszym przykładzie skalar $i
jest wypychany na tablicę @b
jako część List
. Po wypchnięciu wartość przechowywana przez skalar jest wyraźnie aktualizowana w późniejszych iteracjach pętli for za pomocą $i++
instrukcji. Te aktualizacje mają wpływ na wartość w tablicy @b
: na końcu pętli for @b[0;0]
jest równa 3
i już nie 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;
Przykład wyjścia 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
* Przykład 2 * W drugim przykładzie skalar $i
jest zmienną pętli. Nawet jeśli $i
jest aktualizowana po to został zepchnięty (teraz domyślnie zamiast jawnie), wartość $i
w tablicy @c
ma nie
zmienia się po naciśnięciu; czyli po pętli, to jeszcze 2
nie 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;;
Przykład wyjścia 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
Pytanie: Dlaczego $i
w @b
w przykładzie 1 zaktualizowanej po naciśnięciu, podczas gdy $i
w @c
w przykładzie 2 nie jest?
edycja : Po komentarzu @ timotimo zamieściłem wynik .WHERE
w przykładach. Pokazuje to (KTÓRA / logiczna) tożsamość skalarna $i
pozostaje taka sama, podczas gdy jej adres pamięci zmienia się w różnych iteracjach pętli. Nie wyjaśnia to jednak, dlaczego w przykładzie 2 wypchnięty skalar pozostaje związany z tą samą tożsamością KTÓRĄ w połączeniu ze starym adresem („448).
źródło
.WHERE
zamiast tego.WHICH
, zobaczysz, że skalar jest w rzeczywistości innym obiektem za każdym razem wokół pętli. Dzieje się tak, ponieważ spiczaste bloki są „wywoływane”, a podpis jest „związany” przy każdym wywołaniu.Odpowiedzi:
Wartość skalarna to tylko kontener. Możesz myśleć o nich jak o inteligentnym wskaźniku, a nie o prymitywnej wartości.
Jeśli wykonasz zadanie
zmieniasz wartość skalarów, pojemnik pozostaje taki sam.
Rozważać
i
Oba działają zgodnie z oczekiwaniami. Ale: W obu przypadkach rzeczy na liście nie można już modyfikować, ponieważ nie ma kontenera.
dlatego umrze. Więc po prostu użyj zmiennej pętli, prawda?
Nie.
nawet jeśli przejdziemy przez listę zmiennych rzeczy.
Zatem nie ma tu żadnego aliasingu, zamiast tego zmienną pętli jest zawsze ten sam kontener i przypisywane są wartości pochodzące z innych kontenerów.
Możemy to jednak zrobić.
Sposobem na zmodowanie „rzeczy” jest użycie zmiennej pośredniej.
działa w porządku. Lub krótszy i bardziej oryginalny w kontekście
Zobacz też:
https://perl6advent.wordpress.com/2017/12/02/#theoneandonly https://docs.perl6.org/language/containers
źródło
($x,1)
, można również zrobić[$x,1]
który będzie utworzyć nowy pojemnik (także1
, BTW)Int
obiektu ->Int
zostaje zastąpiony pętlą -> kontener wskazuje na nowyInt
), ale drugi nie.Po pewnym czasie zabawy i zastanowienia się nad moim powyższym pytaniem, postawię odpowiedź ... To z mojej strony czysta hipoteza, więc nie wahaj się powiedzieć, że to nie ma sensu, jeśli tak, a jeśli się dowiesz, dlaczego...
W pierwszym przykładzie
$i
jest zdefiniowany poza zakresem leksykalnym pętli for. W konsekwencji$i
istnieje niezależnie od pętli i jej iteracji. Gdy$i
jest wywoływany z wnętrza pętli, istnieje tylko jeden, na$i
który można wpłynąć. To jest to,$i
co jest wpychane@b
, a jego zawartość jest następnie modyfikowana w pętli.W drugim przykładzie
$i
zdefiniowano wewnątrz zakresu leksykalnego pętli for. Jak wskazał @timotimo, wskazany blok jest wywoływany dla każdej iteracji, jak podprogram;$i
jest zatem świeżo zadeklarowany dla każdej iteracji i objęty odpowiednim blokiem. Kiedy$i
odwołuje się do pętli, odnosi się do specyficznej dla iteracji bloku$i
, która normalnie przestałaby istnieć, gdy kończy się odpowiednia iteracja pętli. Ale ponieważ w pewnym momencie$i
jest on popychany@c
, odwołanie do$i
wartości trzymania specyficznej dla iteracji bloku2
nie może zostać usunięte przez śmieciarz po zakończeniu iteracji. Będzie istniał ... ale nadal będzie inny niż$i
w późniejszych iteracjach.źródło