在Perl中,未初始化的哈希键是否具有默认值零?

时间:2009-05-01 14:10:43

标签: perl hash default-value

我的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中未初始化的哈希键自动具有零值?

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

4 个答案:

答案 0 :(得分:26)

该值不会自动为零。该值最初未定义。但是,如果您将其视为数字(例如,将++应用于它),则Perl会将其视为零。如果你将它视为一个字符串(例如,将.应用于它),那么Perl将其视为空字符串。

来自perldoc perlsyn,在'声明'下:

  

您需要申报的唯一内容   Perl是报告格式和   子程序(有时甚至不是   子程序)。变量持有   未定义的值(“undef”),直到它有   被分配了一个定义的值,其中   除了“undef”之外的任何东西。什么时候   用作数字,“undef”被处理   为0;当用作字符串时,它是   被视为空字符串,“”;和   当用作参考时不是   被分配给它,它被视为一个   错误。

答案 1 :(得分:5)

详细说明Telemachus的帖子,未初始化的值将是未定义的。结构的深部是autovivified。这是一个方便的功能,可以自动为您创建数据结构。当你想要它时,自动复原很棒,但是当你想要防止它时它会很痛苦。在了解自动生成的过程中,网上有很多教程,文章和帖子。

因此,如果给定未定义的$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]}++;
    }
}

您可以在perllexwarn中找到警告层次结构。

答案 2 :(得分:4)

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

Perl用语中的术语是'autovivified'。

您可能想要做的是使用exists keyword

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

答案 3 :(得分:2)

没有未初始化的哈希。可以未初始化的是特定键的。哈希值只是一个标量值;它与$foo之类的变量没什么区别。

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

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

最后,您自动生成$res->{ipv6}{pa}{$row->[2]}的方式,这是未定义的。请记住,这只是像$foo这样的标量值。行为与说

相同
my $foo;
$foo++;

当您使用未定义的值时,Perl会执行特殊操作。如果将它们用作数字,Perl会将它们转换为0.如果将它们用作字符串,Perl会将它们转换为''(空字符串)。在大多数情况下,如果您启用了警告(您应该这样做),您将获得“使用未初始化的值...”警告。但auto-increment运算符(++)是一个特殊情况。为方便起见,它会在递增之前将值从undef静默转换为0