For loop 推送后标量值是否受影响。。。(拉库)

For loop 推送后标量值是否受影响。。。(拉库),for-loop,raku,indirection,For Loop,Raku,Indirection,我很难理解推式Scalar容器所持有的值在推式之后受到影响的时间和原因。我将尝试用两个程式化的示例来说明我在更复杂的上下文中遇到的问题 *示例1*在第一个示例中,标量$i作为列表的一部分推送到数组@b。推送之后,标量持有的值将在for循环的后续迭代中使用$i++指令显式更新。这些更新对数组@b中的值有影响:在for循环结束时,@b[0;0]等于3,不再等于2 my @b; my $i=0; for 1..3 -> $x { $i++; say 'Loose var $i: ', $

我很难理解推式
Scalar
容器所持有的值在推式之后受到影响的时间和原因。我将尝试用两个程式化的示例来说明我在更复杂的上下文中遇到的问题

*示例1*在第一个示例中,标量
$i
作为
列表的一部分推送到数组
@b
。推送之后,标量持有的值将在for循环的后续迭代中使用
$i++
指令显式更新。这些更新对数组
@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
)会进行更新(现在是隐式而不是显式更新),数组
@c
$i
的值也不会 推后变;i、 e.在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
问题:为什么示例1中的
@b
中的
$i
会在推送后更新,而示例2中的
@c
中的
$i
不会更新

编辑
在@timotimo的评论之后,我在示例中包括了
.WHERE
的输出。这显示了
$i
的(哪个/逻辑)标量标识保持不变,而其内存地址在各种循环迭代中发生变化。但它并没有解释为什么在示例2中,推送的标量与旧地址(“448”)组合后仍然与相同的标识绑定。

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

如果你做作业

$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;
但是:在这两种情况下,列表中的内容不再是可变的,因为没有容器

@b[4;0] = 99; 
所以就使用循环变量,对吗

没有

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

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
很好。或者在原始上下文中更短、更多

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)]
另见:


在玩弄并思考了我的上述问题一段时间后,我敢打赌我会给出一个答案……这纯粹是我的猜测,所以如果是,请随意说这是毫无意义的,如果你碰巧知道,为什么

在第一个示例中,
$i
是在for循环的词法范围之外定义的。因此,
$i
独立于循环及其迭代而存在。当从循环内部引用
$i
时,只有一个
$i
会受到影响。正是这个
$i
被推入
@b
,并在循环中修改其内容


在第二个示例中,
$i
是在for循环的词法范围内定义的。正如@timotimo所指出的,每次迭代都会调用指向的块get,就像一个子例程一样;
$i
因此会为每次迭代新声明,并限定到相应的块。当在循环内引用
$i
时引用是针对特定于块迭代的
$i
,当相应的循环迭代结束时,该引用通常将不存在。但是,由于在某个点
$i
被推送到
@c
,因此垃圾收集器之后无法删除对特定于块迭代的
$i
保持值
2
的引用r迭代的终止。它将保持存在…,但在以后的迭代中仍然不同于
$i

我可以给你答案,为什么它看起来保持不变;看看实现:-它只取决于所使用的描述符,它是一个小对象,包含变量的名称,一个nd类型约束。如果使用
.WHERE
而不是
.WHICH
,则每次循环中都可以看到标量实际上是不同的对象。这是因为“调用”了尖头块,而签名是“绑定”的“在每次调用中,@raiph在循环过程中,示例1显示了与示例2相同的模式:两个都报告了不断变化的地址。WHERE,这说明,我同意。”。但它本身并不能解释为什么示例2的结尾与示例1不同。除了
($x,1)
,你还可以做
[$x,1]
,这将创建一个新的容器(也用于
1
,顺便说一句)@ElizabethMattijsen,但接下来是数组进行“提升”是吗?不确定“提升”是什么意思,但如果您在创建时将这些值打包,那么是的。@Holli谢谢您的回复。但我不确定它是否解决了这个问题。您的答案集中在容器的易变性上,我想我理解这一点。我不明白的是,为什么在第一个示例中,推送容器$I(或者更好:它的值)在推送后更新,而在第二个示例中,推送容器的值在推送时仍然静态地与值绑定。第一个例子对我来说有一定的意义(容器是指向
Int
对象的指针-->
Int
在for循环中被替换->容器指向new
Int
),但第二个没有意义。@Holli我将尝试澄清这个问题。@raiph谢谢。我会的。也许比我更有洞察力的人可以(重新)恰当地表达答案。无论如何,我不会接受我自己的答案是正确的,直到那些知道答案的人确认(或改进)
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)]