Perl 中未初始化的哈希键的默认值是否为零?
-
03-07-2019 - |
题
我有类似于以下的 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 会将它们转换为 '' (空字符串)。在大多数情况下,如果您启用了警告(您应该这样做),您将收到“使用未初始化值...”警告。这 自动递增 操作员 (++
)不过是一个特例。为了方便起见,它默默地将值从 undef
到 0
在增加它之前。