푸시 Scalar
된 컨테이너가 보유한 값 이 푸시 후 영향을받는 시기와 이유를 이해하기가 어렵습니다 . 두 가지 양식화 된 예제에서보다 복잡한 컨텍스트에서 발생한 문제를 설명하려고합니다.
* 예 1 * 첫 번째 예에서 스칼라 $i
는 @b
a의 일부로 배열에 푸시 List
됩니다. 푸시 후 스칼라가 보유한 값은 $i++
명령어를 사용하여 for 루프의 이후 반복에서 명시 적으로 업데이트됩니다 . 이러한 업데이트는 배열의 값에 영향을 미칩니다 @b
. for 루프의 끝에서는 @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;
출력 예 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
* 예 2 * 두 번째 예에서 스칼라 $i
는 루프 변수입니다. $i
푸시 된 후에 업데이트 되지만 (현재 명시 적으로가 아니라 암시 적으로)
푸시 후에 $i
배열 의 값이 변경 @c
되지 않습니다 . 즉, for 루프 후에도 여전히 2
아닙니다 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;;
출력 예 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
질문 : 왜 $i
에 @b
있는 동안, 푸시 후 업데이트 실시 예 1에서 $i
의 @c
예 2에서이 아닌가요?
edit : @timotimo의 의견 .WHERE
에 따라 예제에 출력을 포함 시켰습니다 . 이것은 (WHICH / 논리) 스칼라 ID가 $i
동일하게 유지되고 메모리 주소가 다양한 루프 반복을 통해 변경됨을 나타냅니다. 그러나 예제 2에서 푸시 된 스칼라가 왜 이전 주소 ( “448)와 결합하여 동일한 WHICH ID에 연결되어 있는지에 대해서는 설명하지 않습니다.
답변
스칼라 값은 컨테이너 일뿐입니다. 그것들을 기본 값이 아닌 일종의 스마트 포인터로 생각할 수 있습니다.
과제를하면
$foo = "something"; #or
$bar++;
스칼라 값을 변경하면 컨테이너가 동일하게 유지됩니다.
치다
my @b;
my $i=0;
for 1..5 -> $x {
$i++;
@b.push(($i<>,1)); # decontainerize $i and use the bare value
}
say @b;
과
my @b;
my $i=0;
for 1..5 -> $x {
$i := $i + 1; # replaces the container with value / change value
@b.push(($i,1));
}
say @b;
둘 다 예상대로 작동합니다. 그러나 두 경우 모두 컨테이너가 없기 때문에 목록의 내용은 더 이상 변경할 수 없습니다.
@b[4;0] = 99;
그러므로 죽을 것이다. 그렇다면 루프 변수를 사용하십시오.
아니.
for 1..5 -> $x {
@b.push(($x,1)); #
}
@b[4;0] = 99; #dies
우리가 변경 가능한 것들의 목록을 반복하더라도.
my $one = 1;
my $two = 2;
my $three = 3;
my $four = 4;
my $five = 5;
for ($one, $two, $three, $four, $five) -> $x {
@b.push(($x,1));
}
@b[4;0] = 99; #dies
따라서 여기서 발생하는 앨리어싱이 없으며 대신 루프 변수는 항상 동일한 컨테이너이며 다른 컨테이너에서 오는 값이 할당됩니다.
그래도 가능합니다.
for ($one, $two, $three, $four, $five) <-> $x {
@b.push(($x,1));
}
@b[4;0] = 99; # works
for ($one, $two, $three, $four, $five) -> $x is rw {
@b.push(($x,1));
}
@b[4;0] = 99; # works too
“사물”을 변경 가능하게하는 방법은 중간 변수를 사용하는 것입니다.
for 1..5 -> $x {
my $j = $x;
@b.push(($j,1)); # a new container
}
@b[4;0] = 99;
잘 작동합니다. 또는 원래 상황에서 더 짧거나 더
my @b;
my $i=0;
for 1..5 -> $x {
$i++;
@b.push((my $ = $i, 1)); # a new anonymous container
}
@b[4;0] = 99;
say @b; # [(1 1) (2 1) (3 1) (4 1) (99 1)]
또한보십시오:
https://perl6advent.wordpress.com/2017/12/02/#theoneandonly
https://docs.perl6.org/language/containers
답변
잠시 동안 위의 질문에 대해 생각하고 생각한 후에, 나는 대답을 베풀 것입니다 … 그것은 순수한 추측입니다. 그렇다면 말도 안된다고 말하고, 알고 있다면, 왜…
첫 번째 예에서는 $i
for 루프의 어휘 범위 외부에서 정의됩니다. 결과적으로 $i
루프 및 반복과 독립적으로 존재합니다. $i
루프 내부에서 참조 될 때 $i
영향을받을 수있는 것은 하나뿐입니다 . 이것은로 $i
푸시되어 @b
나중에 루프에서 내용이 수정됩니다.
두 번째 예에서는 $i
for 루프의 어휘 범위 내에 정의되어 있습니다. @timotimo가 지적했듯이 뾰족한 블록은 서브 루틴처럼 각 반복마다 호출됩니다. $i
따라서 각 반복에 대해 새롭게 선언되고 해당 블록으로 범위가 지정됩니다. $i
루프 내에서 참조 되면 블록 반복 특정 참조가 발생하며 $i
, 이는 일반적으로 각 루프 반복이 종료되면 존재하지 않습니다. 그러나 어떤 시점에서 $i
로 푸시 @c
되었으므로 반복 종료 후 가비지 콜렉터 가 블록 반복 특정 $i
보유 값에 대한 참조를 2
삭제할 수 없습니다. 그것은 계속 존재하지만 $i
나중에 반복 되는 것과는 여전히 다릅니다 .