Ich habe Schwierigkeiten zu verstehen, wann und warum der Wert eines Scalar
Push-Containers nach dem Push beeinflusst wird. Ich werde versuchen, das Problem, auf das ich in einem komplizierteren Kontext gestoßen bin, in zwei stilisierten Beispielen zu veranschaulichen.
* Beispiel 1 * Im ersten Beispiel wird ein Skalar als Teil von a $i
auf ein Array verschoben . Nach dem Push wird der vom Skalar gehaltene Wert in späteren Iterationen der for-Schleife unter Verwendung der Anweisung explizit aktualisiert . Diese Aktualisierungen wirken sich auf den Wert im Array aus : Am Ende der for-Schleife ist gleich und nicht mehr gleich .@b
List
$i++
@b
@b[0;0]
3
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;
Ausgabebeispiel 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
* Beispiel 2 * Im zweiten Beispiel ist der Skalar $i
die Schleifenvariable. Auch wenn $i
aktualisiert wird , nachdem es (jetzt eher implizit als explizit), den Wert gedrückt wurde $i
in Array @c
ist nicht
ändern , nachdem der Druck; dh nach der for-Schleife ist es immer noch 2
nicht 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;;
Ausgabebeispiel 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
Frage: Warum ist $i
in @b
Beispiel 1 nach dem Push aktualisiert, während $i
in @c
Beispiel 2 ist das nicht?
edit : Nach dem Kommentar von @ timotimo habe ich die Ausgabe von .WHERE
in die Beispiele aufgenommen. Dies zeigt, dass die (WELCHE / logische) Skalaridentität von gleich $i
bleibt, während sich ihre Speicheradresse durch die verschiedenen Schleifeniterationen ändert. Es erklärt jedoch nicht, warum in Beispiel 2 der Push-Skalar in Kombination mit einer alten Adresse ("448) an dieselbe WHICH-Identität gebunden bleibt.
quelle
.WHERE
stattdessen verwenden.WHICH
, können Sie sehen, dass der Skalar jedes Mal um die Schleife herum ein anderes Objekt ist. Dies geschieht, weil spitze Blöcke "aufgerufen" werden und die Signatur bei jedem Aufruf "gebunden" wird.Antworten:
Ein Skalarwert ist nur ein Container. Sie können sie sich eher als eine Art intelligenten Zeiger als als einen primitiven Wert vorstellen.
Wenn Sie eine Aufgabe machen
Wenn Sie den Skalarwert ändern, bleibt der Container gleich.
Erwägen
und
Beide funktionieren wie erwartet. Aber: In beiden Fällen ist das Objekt in der Liste nicht mehr veränderbar, da es keinen Container gibt.
wird daher sterben. Verwenden Sie also einfach die Schleifenvariable, oder?
Nein.
selbst wenn wir eine Liste veränderlicher Dinge durchlaufen.
Hier findet also kein Aliasing statt, stattdessen ist die Schleifenvariable immer derselbe Container und erhält zugewiesene Werte, die von den anderen Containern stammen.
Wir können das aber tun.
Eine Möglichkeit, "das Ding" veränderbar zu machen, ist die Verwendung einer Zwischenvariablen.
funktioniert gut. Oder kürzer und mehr im ursprünglichen Kontext
Siehe auch:
https://perl6advent.wordpress.com/2017/12/02/#theoneandonly https://docs.perl6.org/language/containers
quelle
($x,1)
, können Sie auch tun ,[$x,1]
das würde einen neuen Container (auch für erstellen1
, BTW)Int
Objekt ->Int
wird in for-Schleife ersetzt -> Container zeigt auf neuInt
), das zweite nicht.Nachdem ich einige Zeit mit meiner obigen Frage gespielt und darüber nachgedacht habe, werde ich eine Antwort wetten ... Es ist eine reine Vermutung meinerseits, also zögern Sie nicht zu sagen, dass es unsinnig ist, wenn es so ist und wenn Sie es zufällig wissen, Warum...
Im ersten Beispiel
$i
wird außerhalb des lexikalischen Bereichs der for-Schleife definiert. Folglich$i
existiert unabhängig von der Schleife und ihren Iterationen. Wenn$i
innerhalb der Schleife auf sie verwiesen wird$i
, kann nur eine betroffen sein. Es ist dies$i
, das hineingeschoben@b
wird und dessen Inhalt anschließend in der Schleife geändert wird.Im zweiten Beispiel
$i
wird innerhalb des lexikalischen Bereichs der for-Schleife definiert. Wie @timotimo hervorhob, wird der spitze Block für jede Iteration aufgerufen, wie eine Unterroutine;$i
wird daher für jede Iteration neu deklariert und auf den jeweiligen Block beschränkt. Wenn$i
innerhalb der Schleife referenziert wird, bezieht sich die Referenz auf die blockiterationsspezifische$i
, die normalerweise nicht mehr existiert, wenn die jeweilige Schleifeniteration endet. Weil aber an einem gewissen Punkt$i
zu gedrückt wird@c
, die Bezugnahme auf den Block-Iteration spezifischen$i
Haltewert2
kann nicht durch den Speicherbereinigungs nach Beendigung der Iteration gelöscht werden. Es wird bestehen bleiben ..., sich aber immer noch von$i
späteren Iterationen unterscheiden.quelle