5

我需要验证哈希元素的 Perl 哈希$Table{$key1}{$key2}是否存在和被定义。这就是我所做的。(我$key1什至不知道存在)

if 
((defined $Table{$key1}) &&
 (exists  $Table{$key1}) &&
 (defined $Table{$key1}{$key2}) &&
 (exists  $Table{$key1}{$key2})) 
{
   #do whatever
}

有没有更简单、更清洁的方法来做到这一点?

4

5 回答 5

8

你不需要检查每个层次的层次结构:你可以只追求你关心的价值。exists仅当哈希中的插槽存在时才检查定义性(它可能存在未定义的值),因此如果您关心该值已定义,则需要调用defined而不是存在。如果未定义值,则它在布尔上下文中评估为 false,因此我们可以少输入一点并将您的示例简化为:

if ($Table{$key1}{$key2})
{
   # do whatever
}

但是,如果该键中的值已定义但为“假”(数值计算为零,或者是空字符串),则可能导致误报,因此如果有可能,我们应该显式检查定义性:

if (defined $Table{$key1}{$key2})
{
   # do whatever
}

如果您不想 autovivify $Table{$key1},您可以先检查它的存在,这将我们带到一般情况下的“最佳”方式

if (exists $Table{$key1} and defined $Table{$key1}{$key2})
{
   # do whatever
}

如果您要对散列中的各个字段执行大量此操作,您可能需要添加一些 OO 样式的访问器方法来为您完成这项工作:

sub has_field
{
    my ($this, $fieldName) = @_;
    return exists $this->{data} && defined $this->{data}{$fieldName});
}

我确定您已经阅读过它,但是再次阅读相关文档不会有什么坏处:

给定一个指定哈希元素或数组元素的表达式,exists如果哈希或数组中的指定元素曾经被初始化,则返回 true,即使相应的值未定义。如果元素不存在,则不会自动激活该元素。
...
哈希或数组元素只有在定义时才为真,如果存在则定义,但反过来不一定成立。

于 2010-04-27T17:42:25.070 回答
6

以下内容更短,可以防止自动存活:

 if (exists $table{$key1} and defined $table{$key1}{$key2}) {...}

不需要代码中的其他检查。

于 2010-04-27T17:46:27.440 回答
1

您可以查看Data::Diver。它潜入数据结构而不自动激活。语法是:

if ( defined Dive(\%Table, $key1, $key2) ) { ... }

甚至:

if ( defined(my $value = Dive(\%Table, $key1, $key2) ) ) {
  ...do something with $value...
}
于 2010-04-27T21:47:42.137 回答
1

首先检查存在性,然后检查定义性。(一个值可以存在而不被定义,但不能被定义而不存在。)您应该测试中间级别exists以防止意外自动激活。对于最后一个级别,您只需调用defined. 当没有太多层时,直接编码很容易:

if (exists $hash{a} && defined $hash{a}{b}) {...}

如果有很多层,这会变得很尴尬:

if (exists $hash{a} && exists $hash{a}{b} && exists $hash{a}{b}{c} ...) {...}

在这种情况下,您可以编写一个defined不会自动激活中间值的版本:

sub safe_defined {
    my $h = shift;

    foreach my $k (@_) {
        if (ref $h eq ref {}) {
            return unless exists $h->{$k};
            $h = $h->{$k};
        }
        else {
            return;
        }
    }

    return defined $h;
}

你这样使用它:

if (safe_defined(\%hash, qw(a b c))) {
     say $hash{a}{b}{c};
}

注意:此版本的功能是有限的。

  • 它只处理嵌套哈希。Perl 允许您构建任意数据结构,例如标量引用数组的哈希...
  • 它不支持祝福引用(即对象)。

一个真正通用的版本留给读者作为练习。;)

于 2010-04-27T19:39:30.243 回答
0

伟大的!谢谢大家的回复。

由于自动激活对我来说是一个问题,目前我正在使用“尴尬”的方法,即 if (exists $Table{$key1} && defined $Table{$key1}{$key2}) {

做任何事

}

它对我有用,但是正如你们所说,我有 3-4 级深度的嵌套哈希,代码有点乱。

我将检查数据:潜水员。那个好看点

再次感谢,

于 2010-04-28T17:34:50.073 回答