2

我有以下代码:

#!/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。

4

2 回答 2

3

你在“autovivification”上磕磕绊绊。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 pragma 使可以轻松地在部分代码中关闭 autovivification。所以只需添加:

no autovivification;

在导致问题的代码块中。

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

$ perl -MData::Dumper -E'if ("HASH" eq ref $foo and exists $foo->{bar} and !$foo->{bar}->{baz}){}; say Dumper $foo'
$VAR1 = undef;
于 2020-08-20T14:21:21.597 回答
1

正如Dave Cross所指出的,这是autovivification。通常,您无需担心它,除非您在某些时候基于此哈希键的存在做出假设,或者您的数据集太大以至于需要非常仔细的内存调节。

您可以使用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";
}
于 2020-08-20T17:44:25.713 回答