perl检查嵌套哈希引用



我有以下代码:

#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
my $site = "test.com";
my $data = {
"test" => 1
};
my $user = defined($data->{addons}->{$site}->{username}) ? $data->{addons}->{$site}->{username} : "nothing";
print Dumper($data);

结果:

$VAR1 = {
'test' => 1,
'addons' => {
'test.com' => {}
}
};

正如您所看到的,如果用户是在嵌套结构中定义的,那么检查实际上会创建一个空键。我的问题是如何在不定义键的情况下检查hashref。

你被"自动活体化";。Perl会自动在您尝试访问的数据结构中创建中间级别。你可以在这里看到它的作用:

$ perl -MData::Dumper -E'if (!$foo->{bar}->{baz}){}; say Dumper $foo'
$VAR1 = {
'bar' => {}
};

为了检查$foo->{bar}->{baz}是否为真,Perl创建了$foo->{bar}。这使得创建复杂的数据结构变得容易,但在查询它们时可能会出现问题。

但看看这个:

$ perl -M-autovivification -MData::Dumper -E'if (!$foo->{bar}->{baz}){}; say Dumper $foo'
$VAR1 = undef;

autovivification杂注可以很容易地关闭代码部分的autovification。所以只需添加:

no autovivification;

在导致问题的代码块中。

更新:还有一种手动方法,包括检查数据结构的每个级别,并在发现与您要查找的内容不匹配时立即停止查找:

$ perl -MData::Dumper -E'if ("HASH" eq ref $foo and exists $foo->{bar} and !$foo->{bar}->{baz}){}; say Dumper $foo'
$VAR1 = undef;

正如Dave Cross所指出的,这是一种自我激活。通常,你不需要担心它,除非你在某个时候根据这个哈希密钥的存在做出假设,或者如果你的数据集太大,需要非常小心地调节内存。

您可以使用no autovivification杂注,最好在有限的词法范围内使用,例如:

my $user;
{  # no autovivification is limited to this block
no autovivification;
$user = $data->{addon}{$site}{username} // "nothing";
}

//是定义的或运算符,在这种情况下使用起来很方便。

但对于这样一个简单的问题,你可能会得到一个更简单的解决方案:

my $user;
if ( defined $data->{addon}{$site} ) {
$user = $data->{addon}{$site}{username} // "nothing";
}

最新更新