1

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

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

与所有遗留代码一样,这个 $value 几乎可以是任何东西(散列、标量、数组),尽管它应该是不同对象的数组。这段代码目前在大约 5% 的时间出现“不是数组引用”而失败,我试图找出可能破坏它的 $value 是什么。

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

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

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

我正在使用 perl 5.8。

4

2 回答 2

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,当取消引用并强制转换为标量时,变成一个字符串,其中第一个数字是键的数量,第二个数字是哈希表中的桶数:2/8
于 2018-11-16T12:47:41.990 回答
1

以下代码将解决:

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

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

于 2018-11-16T12:36:54.623 回答