[for-loop] 푸시 후 영향을받는 스칼라 값… (Raku)

푸시 Scalar된 컨테이너가 보유한 값 이 푸시 후 영향을받는 시기와 이유를 이해하기가 어렵습니다 . 두 가지 양식화 된 예제에서보다 복잡한 컨텍스트에서 발생한 문제를 설명하려고합니다.

* 예 1 * 첫 번째 예에서 스칼라 $i@ba의 일부로 배열에 푸시 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


답변

잠시 동안 위의 질문에 대해 생각하고 생각한 후에, 나는 대답을 베풀 것입니다 … 그것은 순수한 추측입니다. 그렇다면 말도 안된다고 말하고, 알고 있다면, 왜…

첫 번째 예에서는 $ifor 루프의 어휘 범위 외부에서 정의됩니다. 결과적으로 $i루프 및 반복과 독립적으로 존재합니다. $i루프 내부에서 참조 될 때 $i영향을받을 수있는 것은 하나뿐입니다 . 이것은로 $i푸시되어 @b나중에 루프에서 내용이 수정됩니다.

두 번째 예에서는 $ifor 루프의 어휘 범위 내에 정의되어 있습니다. @timotimo가 지적했듯이 뾰족한 블록은 서브 루틴처럼 각 반복마다 호출됩니다. $i따라서 각 반복에 대해 새롭게 선언되고 해당 블록으로 범위가 지정됩니다. $i루프 내에서 참조 되면 블록 반복 특정 참조가 발생하며 $i, 이는 일반적으로 각 루프 반복이 종료되면 존재하지 않습니다. 그러나 어떤 시점에서 $i로 푸시 @c되었으므로 반복 종료 후 가비지 콜렉터 가 블록 반복 특정 $i보유 값에 대한 참조를 2삭제할 수 없습니다. 그것은 계속 존재하지만 $i나중에 반복 되는 것과는 여전히 다릅니다 .


답변