自动设置为undef的数组元素在别名时不会改变?

时间:2013-08-06 21:59:24

标签: perl

关于this问题,手动设置之间的区别是什么 到undef列表元素和Perl在增加大小时设置的元素 当列表时,通过分配比列表大小更大的索引来列出该列表 走样?例如,考虑以下代码:

@a = (undef, 0);
@b = ();
$b[1] = 0;

print Dumper(@a), "\n", Dumper(@b);

它打印(按照预期,我认为):

$VAR1 = undef;
$VAR2 = 0;

$VAR1 = undef;
$VAR2 = 0;

那么,数组不一样吗?显然不是:

sub change { $_[0] = 1 }
change(@a); change(@b);
print Dumper(@a), "\n", Dumper(@b);

打印哪些:

$VAR1 = 1;
$VAR2 = 0;

$VAR1 = undef;
$VAR2 = 0;

2 个答案:

答案 0 :(得分:17)

你找到了一个引人入胜的边缘案例。

当您明确设置元素时,它首先会存在。如果扩展数组以使多个索引落入此数组的范围内,则不会在这些位置隐式初始化标量。例如:

my @array;
$array[2] = undef; # this extends the array
# now elements 0–2 report as `undef`, but only #2 was initalized

当我们询问这些元素是否存在时,我们得到:

say "index $_ ", exists $array[$_] ? "exists" : "doesn't exist" for 0 .. 4;

输出:

index 0 doesn't exist
index 1 doesn't exist
index 2 exists
index 3 doesn't exist
index 4 doesn't exist

此优化可以避免在这些位置分配未使用的标量;当没有任何说明的情况下,数组访问代码只返回undef

现在这与函数调用非常相似。调用子例程时,会在堆栈上放置一个平面的标量列表,然后可以将其作为@_访问。这里没有复制,所以这是别名调用。现在,当您在子资源中访问$_[0]元素时,此处没有标量,因此它会在@_中创建一个新标量:

sub crazy {
  say 1*exists $_[0];
  $_[0] = 1;
  say 1*exists $_[0];
}

my @array; $array[2] = 0;
crazy @array;

say 1*exists $array[0];

输出:

0
1
0

在内部,标量是指向SV结构的指针。这些指针被复制到堆栈中,因此这使得原始@array的实际修改成为不可能。

答案 1 :(得分:6)

一个区别是exists $a[0]为真,exists $b[0]为假。