【问题标题】:Perl Warning on Iterating a Hash迭代哈希的 Perl 警告
【发布时间】:2014-10-27 05:27:34
【问题描述】:

下面的代码通过给出这个警告消息让我困惑了一段时间:Use of uninitialized value in join or string at ./mycode.pl line 666. where line 666: print "@{n0->{$x}{$y}}\n";。请注意,n 是字符串数组的哈希值,如下所示:

n  = (
 x0 => {
   y0 => [ "foo00", "bar00" ]
   y1 => [ "foo01", "bar01" ]
   ...
 }
 x1 => {
   y0 => [ "foo10", "bar10" ]
   y1 => [ "foo11", "bar11" ]
   ...
 }
...
)

代码如下:

my $rn =\%n;
for my $x (keys %$rn){
    print "$x\n";
    for my $y (keys %{$rn->{$x}}){
        print "@{$rn->{$x}{$y}}\n";
    }
}

我不明白 Perl 为什么要抱怨uninitialized values。本质上,我希望元素必须具有值,否则它们甚至不会存在,因此不会出现在迭代中。此外,输出符合我的预期。

我在这里想念的症结是什么?我怎样才能摆脱它?

【问题讨论】:

  • 不知道这是不是唯一的问题,但@{rn... 应该是@{$rn...
  • @ysth 谢谢,这是一个错字。我修正了问题描述。
  • 您不应在问题中输入代码。你应该剪切和粘贴你已经运行的代码,你肯定会按照你说的那样工作。在进行故障排除时,我们没有使用近似代码,我们需要细节。最好创建一个 sscce 来证明您的问题。
  • @TLP 我完全按照你说的做了。除了输入 n。检查第一个答案是如何根据问题做出的。
  • @AliAbbasinasab,不,你没有抄袭。因为你的 666 (devil) 行是:print "@{n0->{$x}{$y}}\n"; 所以,而不是你使用n0 的真实代码中的演示代码$rn。所以,它不是“副本”。 ;)

标签: perl hash foreach warnings


【解决方案1】:

乍一看,您的代码似乎没有任何问题。因此,您的数据存在问题。

我建议使用Data::Dump(我的偏好)或Data::Dumper 之类的模块来检查您的数据。然后,您不仅可以更轻松地确定哪个键具有错误数据,还可以确定哪个值。

如果你想花哨,你甚至可以创建一个特殊的$SIG{__WARN__} 处理程序,仅在发现错误时输出附加信息。

use strict;
use warnings;

my %n = (
    x0 => {
        y0 => [ "foo00", "bar00" ],
        y1 => [ "foo01", "bar01" ],
    },
    x1 => {
        y0 => [ "foo10", undef ],
        y1 => [ "foo11", "bar11" ],
    },
);

my $rn = \%n;
for my $x ( keys %$rn ) {
    print "$x\n";
    for my $y ( keys %{ $rn->{$x} } ) {
        # Catch Warning and output additional info
        local $SIG{__WARN__} = sub {
            warn @_;   # Output regular warning info
            use Data::Dump;
            dd $x, $y, $rn->{$x}{$y};
        };

        print "@{$rn->{$x}{$y}}\n";
    }
}

输出:

x1
foo11 bar11
Use of uninitialized value in join or string at b.pl line 24.
("x1", "y0", ["foo10", undef])
foo10 
x0
foo01 bar01
foo00 bar00

【讨论】:

  • 黎明,这就是我自 1740 年以来一直在寻找的东西。
【解决方案2】:

以下代码有效;看看你的代码有什么不同。

use strict;
use warnings;

my %n = (
 x0 => {
   y0 => [ "foo00", "bar00" ],
   y1 => [ "foo01", "bar01" ]
 },
 x1 => {
   y0 => [ "foo10", "bar10" ],
   y1 => [ "foo11", "bar11" ]
 }
);

my $rn =\%n;
for my $x (keys %$rn){
    print "$x\n";
    for my $y (keys %{$rn->{$x}}){
        print "@{$rn->{$x}{$y}}\n";
    }
}

也许您的数据与您想象的不完全一样? 添加use Data::Dumper; print Data::Dumper->new([$rn])->Useqq(1)->Terse(1)->Dump; 看看是否有任何线索。

您可以通过将其放在打印之前跟踪哪些值特别触发了警告:

local $SIG{__WARN__} = sub { print "warning given when x is $x and y is $y: ", @_ };

也就是说,除非其中一个数组元素未定义,否则我根本不会发出警告,除非我将 $" 设置为 undef(尽管您使用的是 perl 的古老版本而我不是,所以这可能会有所不同。)如果实际上您正在更改$"(通常是空格字符),则应避免在字符串中插入数组,而是明确地这样做:

print join(" ", @{$rn->{$x}{$y}}), "\n";

【讨论】:

  • 我是否可以看到针对哪个特定迭代发出了警告?
  • 大概您会看到哪个键发出警告,因为您正在打印键。但这真的没有必要。如果您使用Data::Dumper 打印数据结构,您将亲眼看到undef 的值在哪里。
猜你喜欢
  • 2023-04-07
  • 2017-09-04
  • 2016-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多