我有类似于以下的 Perl 代码:

# -- start --

my $res;

# run query to fetch IPv6 resources
while( my $row = $org_ip6_res->fetchrow_arrayref )
{
    if( $row->[4] =~ /PA/ ) {
        $res->{ipv6}{pa}{$row->[2]}++;
    } elsif( $row->[4] eq 'PI' ) {
        $res->{ipv6}{pi}{$row->[2]}++;
    }
}

# -- stop --

任何时候都不是 $res 在迭代查询结果之前曾经设置过,但代码运行得很好。

当我将 print 语句放在每个值之前时,在两种情况下我都会得到空白,但如果 print 语句出现在应用增量之后,我会得到 >= 1 的值,具体取决于组织拥有多少 IPv6 资源。

我的问题是,我是否认为这意味着 Perl 中未初始化的哈希键自动具有零值?

抱歉,如果它是一个新手问题,但我只是不熟悉这样的结构IE $hashref->{foo}->{bar}++其中值尚未显式分配给 $hashref->{foo}->{bar}. 。提前致谢!

有帮助吗?

解决方案

该值不会自动为零。该值最初是未定义的。但是,如果您将其视为数字(例如,应用 ++ 到它),然后 Perl 将其视为零。如果您将其视为字符串(例如,应用 . 到它),然后 Perl 将其视为空字符串。

perldoc perlsyn, ,在“声明”下:

您唯一需要以Perl声明的内容是报告格式和子例程(有时甚至不是子例程)。一个变量保存不确定的值(“ Undef”),直到为其分配了一个定义的值,这是“ undef”以外的任何东西。当用作数字时,“ undef”被视为0;当用作字符串时,它被视为空字符串,“”;当用作未分配给的参考时,它被视为错误。

其他提示

为了详细说明 Telemachus 的帖子,未初始化的值将是未定义的。结构的深层部分是 自动活化. 。这是一个方便的功能,可以自动为您创建数据结构。当你想要它时,自动复活是很棒的,但当你想阻止它时,它可能会很痛苦。网上有很多关于理解自动生存的教程、文章和帖子。

所以给定一个未定义的 $ref$ref->{ipv6}{pa}{'foo'}++, $ref 将被赋值为:

$ref = { 
     ipv6 => { 
          pa => { 
              foo => undef
          }
     }
};

然后 undef 将递增,因为 undef 数值化为 0,所以我们得到 0++,即 1。对于最终结果: ref->{ipv6}{pa}{'foo'} == 1.

如果您启用了警告,(您可以 use warnings;, ,不是吗?)当您对这些未定义的值进行操作时,您将收到“未初始化值”警告。如果增加单位化值是所需的行为,那么您可以在代码的有限部分上关闭所需的警告组:

use strict;
use warnings;
my $res;

// run query to fetch IPv6 resources
while( my $row = $org_ip6_res->fetchrow_arrayref )
{   no warnings 'uninitialized';
    if( $row->[4] =~ /PA/ ) {
        $res->{ipv6}{pa}{$row->[2]}++;
    } elsif( $row->[4] eq 'PI' ) {
        $res->{ipv6}{pi}{$row->[2]}++;
    }
}

您可以在以下位置找到警告层次结构 佩勒克斯警告.

它基本上是未定义的,但当您递增它时,它会被视为零。

Perl 术语中的术语是“autovivified”。

您可能想要做的是使用 存在关键字:

$res->{ipv6}{pa}{$row->[2]}++ if exists($res->{ipv6}{pa}{$row->[2]});

不存在未初始化的哈希这样的东西 钥匙. 。可以未初始化的是 价值 对于特定的键。哈希值只是一个标量值;它与像这样的变量没有什么不同 $foo.

在您的示例中,有几个不同的 Perl 功能在交互。

最初 $res 未定义(即它有价值 undef)。当您使用未初始化的值作为哈希引用时(如 $res->{ipv6}...) Perl 将其“自动激活”为一个。也就是说,Perl 创建一个匿名散列并替换 undef 并引用新的哈希值。每次您使用结果值作为参考时,都会重复此过程(无提示)。

最终,你以自己的方式自动复活 $res->{ipv6}{pa}{$row->[2]}, ,这是未定义的。请记住,这只是一个标量值,例如 $foo. 。行为与说的一样

my $foo;
$foo++;

当您使用未定义的值时,Perl 会做一些特殊的事情。如果将它们用作数字,Perl 会将它们转换为 0。如果将它们用作字符串,Perl 会将它们转换为 '' (空字符串)。在大多数情况下,如果您启用了警告(您应该这样做),您将收到“使用未初始化值...”警告。这 自动递增 操作员 (++)不过是一个特例。为了方便起见,它默默地将值从 undef0 在增加它之前。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top