我在Perl脚本中收到错误Can't use an undefined value as an ARRAY reference
。以下是高度简化的版本。
基本上我已经设置了一个数组哈希,其中一些可能是空的(在这种情况下为B)。如果我不对数据数组进行排序,它的工作正常。我已经尝试添加一个条件来测试该特定数组是否存在,但它在此设置中并不喜欢。在数组填充时对它进行排序并不容易(与此示例不同)。
use strict;
use warnings;
my @list = ('A', 'B', 'C');
my %data_for;
$data_for{'A'} = ['apple', 'astronaut', 'acorn'];
$data_for{'C'} = ['car', 'cook', 'candy'];
# Creates error
foreach my $letter (@list) {
print "$letter: ";
foreach my $item ( sort @{$data_for{$letter}}) {
print "$item, ";
}
print "\n";
}
这是我想要的输出(似乎很明显,但是呃):
A: acorn, apple, astronaut,
B:
C: candy, car, cook,
另外,如果我首先打印工作版本(没有排序),那么排序的第二个版本可以正常运行而不会出错。我不明白这一点,但我可以将其作为一种解决方法。
答案 0 :(得分:4)
$data_for{B}
未定义,因此尝试将其取消引用为数组(在sort @{$data_for{$letter}}
表达式中)是一个错误。
一种解决方法是为$data_for{B}
分配一个(空)值:
$data_for{'A'} = ['apple', 'astronaut', 'acorn'];
$data_for{'B'} = [];
$data_for{'C'} = ['car', 'cook', 'candy'];
但更常见的解决方法是使用'||'运算符(或Perl的'//'运算符> = v5.10)在未定义哈希值时指定默认值
foreach my $item ( sort @{$data_for{$letter} || []}) { ... }
如果$data_for{$letter}
未定义(因此计算结果为false),则表达式$data_for{$letter} || []
将计算为对空数组的引用,并且数组取消引用操作将成功。
答案 1 :(得分:2)
因此,您需要检查$data_for{$letter}
是否为引用。可能的检查:
exists($data_for{$letter})
。defined($data_for{$letter})
因为未定义的哈希元素未定义。$data_for{$letter}
因为引用始终为真。我们可以使用支票为我们提供取消引用的内容:
sort @{ $data_for{$letter} // [] }
我们可以使用支票来避免解除引用。
sort $data_for{$letter} ? @{ $data_for{$letter} } : ()
这给了我们以下内容:
print "$letter: ";
for my $item ( sort $data_for{$letter} ? @{ $data_for{$letter} } : () ) {
print "$item, ";
}
print "\n";
或者更好的是,我们可以使用以下内容避免跟踪,
:
use feature qw( say );
say "$letter: ", join ", ", sort $data_for{$letter} ? @{ $data_for{$letter} } : ();
如果我不对数据数组进行排序,它的工作正常。
当您取消引用用作可修改值(左值)的未定义变量时,Perl将自动创建相应类型的变量,并且它将在未定义变量中放置对新创建的变量的引用。这被称为“autovivification”。
由于自动更新仅发生在左值上下文中,因此在其他地方解除未定义的值会导致错误。
my ($a,$b); # Both are undefined.
@$a = @b; # OK. Equivalent to @{ $a //= [] } = @b.
@a = @$b; # XXX. "Can't use an undefined value as an ARRAY reference."
sort
不会修改其操作数,因此它不会在左值上下文中对它们进行求值。
foreach循环在左值上下文中计算其操作数以允许for (@$a) { $_ = uc($_); }
。这意味着
for (@{ $data_for{$letter} }) { ... }
隐式修改$data_for{$letter}
,如下所示:
for (@{ $data_for{$letter} //= [] }) { ... }