Perl:计算数组大小时不是数组引用

Perl: not an array reference while calculating array size

我正在尝试理清一些遗留代码,其中对 $value 进行操作的前提条件是它的大小大于 x(其中 x 是硬编码的 int)。这是它目前的样子:

if (scalar(@{$value}) > x) {
    ...
}

与所有遗留代码一样,这个 $value 几乎可以是任何东西(散列、标量、数组),尽管它应该是不同对象的数组。此代码目前在大约 5% 的时间内因 "Not an ARRAY reference" 失败,我正在尝试找出可能破坏它的 $value。

我假设如果 $value 未定义它可能会失败所以我什至给了它一个 || [] 但无济于事(同样的错误):

if (scalar(@{$value || []}) > x) {
    ...
}

我也在想为什么我需要@{}?我的理解是,它在列表上下文中评估 $value,以便标量稍后可以确保我获得大小。这会使代码更健壮,还是我可以直接使用标量 $value? @{} 会做我想做的事吗?

我正在使用 perl 5.8。

下面的代码将解决:

if ($value and ref $value eq 'ARRAY' and @$value > x) { ... }

基本上,只有当它是 ARRAY 引用时,您才能取消对 ARRAY 的引用。所以确保它是一个 ARRAY ref 是必须的,这样它就不会因为 HASH 等而失败

你有两个问题。我会分开回答:

问题:@{}在做什么?

当您写入 @{$thing} 时,您正在 解引用 $thing 到一个数组中。正如您所注意到的,这仅在 $thing 是数组引用时有效。 (其他取消引用运算符是用于散列引用的 %{$thing} 和用于标量引用的 ${$thing}。)

确实需要一个解引用运算符。考虑一下:

my $arrayref = [ 'Alice', 'Bob', 'Charlie' ];
my $hashref  = { x => 4, y => 5 };
my $string   = "Hello, world";
for my $thing ($arrayref, $hashref, $string) {
    print "thing         --> ", $thing, "\n";
    print "scalar(thing) --> ", scalar($thing), "\n";
}

输出:

thing         --> ARRAY(0x7f3b8054e468)
scalar(thing) --> ARRAY(0x7f3b8054e468)
thing         --> HASH(0x7f3b80560678)
scalar(thing) --> HASH(0x7f3b80560678)
thing         --> Hello, world
scalar(thing) --> Hello, world

$thing 强制到标量上下文是没有意义的。 已经是标量了!

问题:如何安全地解除对标量的引用?

如果你不知道$thing中包含什么样的引用,你可以使用Ref::Util来检查它:

use Ref::Util qw( is_arrayref is_hashref );

for my $thing ($arrayref, $hashref, $string) {
    if (is_arrayref($thing)) {
        print "array: thing         --> ", @{$thing}, "\n";
        print "array: scalar(thing) --> ", scalar(@{$thing}), "\n";
    }
    elsif (is_hashref($thing)) {
        print "hash:  thing         --> ", %{$thing}, "\n";
        print "hash:  scalar(thing) --> ", scalar(%{$thing}), "\n";
    }
    else
    {
        print "else:  thing         --> ", $thing, "\n";
    }
}

输出:

array: thing         --> AliceBobCharlie
array: scalar(thing) --> 3
hash:  thing         --> y5x4
hash:  scalar(thing) --> 2/8
else:  thing         --> Hello, world

观察:

  • arrayref 在取消引用时变成其元素的列表。 print 输出每个没有分隔符的元素:AliceBobCharlie
  • arrayref 在取消引用并强制转换为标量时变为元素数:3
  • hashref 在取消引用时变成键和值的列表。 print 输出没有分隔符的每一对:y5x4
  • 当取消引用并强制转换为标量时,hashref 会变成 string,其中第一个数字是键的数量,第二个数字是哈希表中桶的数量: 2/8