17

关于这个 问题,手动设置为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;
4

2 回答 2

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 中访问该元素时,这里没有标量,因此它会在 中创建一个新的@_

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变得不可能。

于 2013-08-06T22:14:30.363 回答
6

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

于 2013-08-06T22:13:48.430 回答