标量值在推送后是否受影响...(Raku)

ozz*_*zzy 11 for-loop indirection perl6 raku

我很难理解何时以及为什么在推送Scalar后会影响推送的容器所持有的价值。我将在两个风格化的示例中尝试说明我在更复杂的上下文中遇到的问题。

*示例1 *在第一个示例中,标量作为a的一部分$i被推到数组@bList。推送之后,使用$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;
Run Code Online (Sandbox Code Playgroud)

输出示例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
Run Code Online (Sandbox Code Playgroud)

*示例2 *在第二个示例中,标量$i是循环变量。即使$i在推送后更新(现在是隐式而不是显式),$iin 的值在 推送后@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;;
Run Code Online (Sandbox Code Playgroud)

输出示例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
Run Code Online (Sandbox Code Playgroud)

问:为什么$i@b例1推后更新,而$i@c例2中是不是?

编辑:在@timotimo的评论之后,我.WHERE在示例中包括的输出。这表明保持的(WHICH /逻辑)标量身份$i不变,而其内存地址通过各种循环迭代而改变。但是,这并没有解释为什么在示例2中,推入的标量与旧地址(“ 448”)结合仍然与同一WHICH身份相关联。

Hol*_*lli 5

标量值只是一个容器。您可以将它们视为一种智能指针,而不是原始值。

如果您做作业

$foo = "something"; #or
$bar++;
Run Code Online (Sandbox Code Playgroud)

您在更改标量值时,容器保持不变。

考虑

my @b; 
my $i=0; 
for 1..5 -> $x { 
  $i++; 
  @b.push(($i<>,1)); # decontainerize $i and use the bare value
} 
say @b;
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

两者都按预期工作。但是:在这两种情况下,列表中的东西都不再可变了,因为没有容器。

@b[4;0] = 99; 
Run Code Online (Sandbox Code Playgroud)

因此会死。那么就使用循环变量吧?

没有。

for 1..5 -> $x { 
  @b.push(($x,1)); # 
} 
@b[4;0] = 99; #dies
Run Code Online (Sandbox Code Playgroud)

即使我们迭代了一系列可变的东西。

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
Run Code Online (Sandbox Code Playgroud)

因此,这里没有发生别名,而是循环变量始终是同一容器,并获取来自其他容器的赋值。

我们可以做到这一点。

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
Run Code Online (Sandbox Code Playgroud)

使“事物”可变的一种方法是使用中间变量。

for 1..5 -> $x { 
  my $j = $x;
  @b.push(($j,1)); # a new container 
} 
@b[4;0] = 99;
Run Code Online (Sandbox Code Playgroud)

工作正常。或更短或更原始的背景

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)]
Run Code Online (Sandbox Code Playgroud)

也可以看看:

https://perl6advent.wordpress.com/2017/12/02/#theoneandonly https://docs.perl6.org/language/containers