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

时间:2018-11-16 12:10:28

标签: perl perl5.8

我试图解开一些旧代码,其中对$ value进行的操作要是它的大小大于x(其中x是硬编码的int)。这是当前的样子:

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

与所有旧版代码一样,该$ value几乎可以是任何值(哈希,标量,数组),尽管它应该是不同对象的数组。该代码当前失败,大约有5%的时间出现“不是ARRAY引用”,我试图找出可能破坏它的$ value是什么。

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

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

我还试图弄清楚为什么我需要@ {}?我的理解是,它在列表上下文中评估$ value,以便标量以后可以确保我得到大小。这会使代码更健壮,还是可以直接使用标量$ value? @ {}甚至可以按照我的想法做吗?

我正在使用perl 5.8。

2 个答案:

答案 0 :(得分:2)

您在那里有两个问题。我将分别回答:

问题:@{}在做什么?

在编写@{$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取消引用并强制为标量后,将成为字符串,其中第一个数字是键的数量,第二个数字是哈希表中的存储桶的数量:{{1} }

答案 1 :(得分:1)

以下代码将解决:

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

基本上,只有当它是ARRAY参考时,才可以取消引用ARRAY。因此必须确保它是ARRAY引用,这样它才不会因HASH等而失败