我最近注意到,在大多数使用赋值的情况下,重新初始化动态变量并没有我期望的语义(然而,绑定的工作方式与我期望的一样(。
具体来说,在此代码中:
sub g {
my $*i = CALLERS::<$*i> // 0;
my $*a1 = CALLERS::<$*a1> // Array.new;
my @*a2 = CALLERS::<@*a2> // Array.new;
$*i++;
$*a1.push: 'v1';
@*a2.push: 'v2';
dd $*i;
dd $*a1;
dd @*a2;
}
sub f {
my $*i = 0;
my $*a1 = Array.new;
my @*a2 = Array.new;
g; g; g;
}
f
我期望3
、["v1", "v1", "v1"]
和["v2", "v2", "v2"]
的输出,但却得到了1
、$["v1", "v1", "v1"]
和["v2"]
。切换到绑定解决了这个问题,所以我不想解决任何问题——但我很想理解为什么分配在这里不起作用。我注意到,指向数组的标量可以工作,但指向Int的标量则不行。但在任何一种情况下,我都会认为新分配的变量将从CALLERS接收值。关于赋值的语义,我缺少什么?
在赋值的语义方面我缺少什么?
我认为你所缺少的与动态变量本身无关。我认为你缺少的是:
my @a = Array.new;
基本上是一个角落。由于单参数规则,它与相同
my @a = ();
与相同
my @a;
因此,在sub f
中的示例中
my @*a2 = Array.new;
in只是在动态变量中设置一个空数组。
然后在sub g
中:
my @*a2 = CALLERS::<@*a2> // Array.new;
基本上只是在做(因为单参数规则(:
my @*a2;
因此,你看不到以前做过的push
,因为每次通话都是新鲜的。
关于sub g
中$*i
的值:这也只是增加调用方$*i
的副本,因此在每次调用中该值都保持在1
。
$*a1
之所以有效,是因为容器化停止了单参数规则的扁平化行为。观察以下两者之间的差异:
sub a(+@a) { dd @a }; a [2,3,4]; # [2,3,4]
和:
sub a(+@a) { dd @a }; a $[2,3,4]; # [[2,3,4],]