我需要验证哈希元素的 Perl 哈希$Table{$key1}{$key2}
是否存在和被定义。这就是我所做的。(我$key1
什至不知道存在)
if
((defined $Table{$key1}) &&
(exists $Table{$key1}) &&
(defined $Table{$key1}{$key2}) &&
(exists $Table{$key1}{$key2}))
{
#do whatever
}
有没有更简单、更清洁的方法来做到这一点?
你不需要检查每个层次的层次结构:你可以只追求你关心的价值。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,即使相应的值未定义。如果元素不存在,则不会自动激活该元素。
...
哈希或数组元素只有在定义时才为真,如果存在则定义,但反过来不一定成立。
以下内容更短,可以防止自动存活:
if (exists $table{$key1} and defined $table{$key1}{$key2}) {...}
不需要代码中的其他检查。
您可以查看Data::Diver。它潜入数据结构而不自动激活。语法是:
if ( defined Dive(\%Table, $key1, $key2) ) { ... }
甚至:
if ( defined(my $value = Dive(\%Table, $key1, $key2) ) ) {
...do something with $value...
}
首先检查存在性,然后检查定义性。(一个值可以存在而不被定义,但不能被定义而不存在。)您应该测试中间级别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};
}
注意:此版本的功能是有限的。
一个真正通用的版本留给读者作为练习。;)
伟大的!谢谢大家的回复。
由于自动激活对我来说是一个问题,目前我正在使用“尴尬”的方法,即 if (exists $Table{$key1} && defined $Table{$key1}{$key2}) {
}
它对我有用,但是正如你们所说,我有 3-4 级深度的嵌套哈希,代码有点乱。
我将检查数据:潜水员。那个好看点
再次感谢,