【发布时间】:2020-02-03 13:48:45
【问题描述】:
我很难理解被推送的Scalar 容器所持有的值何时以及为何在推送后受到影响。我将尝试在两个程式化的示例中说明我在更复杂的上下文中遇到的问题。
*示例 1 * 在第一个示例中,标量 $i 被推送到数组 @b 作为 List 的一部分。推送之后,标量保存的值在 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 的值不
推送后更改;即在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 的(WHICH/逻辑)标量标识保持不变,而其内存地址通过各种循环迭代发生变化。但它没有解释为什么在示例 2 中推送的标量仍然绑定到相同的 WHICH 身份以及旧地址(“448)”。
【问题讨论】:
-
我可以告诉你为什么 WHICH 似乎保持不变;查看实现:github.com/rakudo/rakudo/blob/master/src/core.c/Scalar.pm6#L8 - 它仅取决于所使用的描述符,这是一个包含变量名称和类型约束等内容的小对象。如果您使用
.WHERE而不是.WHICH,您可以看到标量实际上每次循环都是不同的对象。发生这种情况是因为尖块被“调用”,并且每次调用都“绑定”了签名。 -
@raiph 在循环期间,示例 1 显示了与示例 2 相同的模式:两者都具有由 .WHERE 报告的更改地址,这说明了,我同意。但它本身并不能解释为什么示例 2 的结局与示例 1 不同。
标签: for-loop raku indirection