【问题标题】:Handling missing references处理缺失的引用
【发布时间】:2017-12-18 19:11:10
【问题描述】:

我在 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,

奇怪的是,如果我首先打印工作版本(不带排序),那么带有排序的第二个版本可以正常工作。我不明白这一点,但我可以将其用作解决方法。

【问题讨论】:

  • 加一个用于提出一个更简单的示例来演示您的问题
  • @mob - 我会说考虑到数组散列的复杂程度,我别无选择,但我知道有些可能有多糟糕。从技术上讲,这个问题是重复的,但我根本无法理解之前那些代码不连贯的问题,这会导致答案不完整。
  • 我很惊讶它甚至没有进入 Merriam-Webster,但 setup 没有任何地方的英语动词。似乎有一种从短语中删除空格的时尚,这使得美式英语越来越像德语。我不喜欢它。很抱歉,这太离题了。
  • @Borodin - 它可能是一个重复的问题标题,但该代码没有清楚地显示问题出在哪里,并且接受的答案是“使用诊断。关于这个相同的错误代码还有另一个问题,但是代码太混乱了,以至于他们无法弄清楚它是用什么写的(perl、python、php??)——最终的答案是“使用诊断”。我的问题得到了一个实际的答案,可以解释什么是错误的。
  • 重新打开,但在这个被标记为重复的问题上没有任何用处。 This one 是一个实际的副本,但我宁愿关闭旧的,而不是这个更清晰的新的。我已经这样做了。

标签: arrays perl sorting hash


【解决方案1】:

$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} || [] 计算结果为对空数组的引用,并且数组取消引用操作将成功。

【讨论】:

    【解决方案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 将自动创建一个适当类型的变量,并将对新创建变量的引用放置在未定义变量中。这被称为“自动复活”。

    由于自动激活仅发生在左值上下文中,因此在其他地方取消引用未定义的值会导致错误。

     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} //= [] }) { ... }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-29
      • 1970-01-01
      • 2020-05-09
      • 1970-01-01
      相关资源
      最近更新 更多