如何检查某个键是否存在于深层 Perl 哈希中?
如果我理解正确,调用 if (exists $ref->{A }->{B}->{$key}) { ... }
将出现 $ref->{A}
和 $ref- >{A}->{B}
即使它们在 if
之前不存在!
这似乎是非常不受欢迎的。那么我应该如何检查“深层”哈希键是否存在?
If I understand correctly, calling if (exists $ref->{A}->{B}->{$key}) { ... }
will spring into existence $ref->{A}
and $ref->{A}->{B}
even if they did not exist prior to the if
!
This seems highly unwanted. So how should I check if a "deep" hash key exists?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
最好使用 autovivification 模块来关闭该功能,或者使用 Data::Diver。然而,这是我希望程序员知道如何自己完成的简单任务之一。即使您在这里不使用该技术,您也应该知道它可以解决其他问题。这本质上就是
Data::Diver
剥离其接口后所做的事情。一旦你掌握了遍历数据结构的技巧(如果你不想使用为你做这件事的模块),这很容易。在我的示例中,我创建了一个
check_hash
子例程,该子例程采用哈希引用和要检查的键的数组引用。它一次检查一个级别。如果密钥不存在,则不会返回任何内容。如果密钥存在,它将哈希修剪为路径的该部分,并再次尝试使用下一个密钥。诀窍在于$hash
始终是树中要检查的下一个部分。我将exists
放入eval
中,以防下一个级别不是哈希引用。诀窍是如果路径末尾的哈希值是某种错误值,则不会失败。这是任务的重要部分:不要被接下来的所有代码吓到。重要的部分就是
check_hash
子例程。其他一切都是测试和演示:这是输出(减去数据转储):
现在,您可能需要进行一些其他检查,而不是
exists
。也许您想检查所选路径的值是否为真,或者是字符串,或者另一个散列引用,或者其他什么。只需在验证路径存在后提供正确的检查即可。在此示例中,我传递了一个子例程引用,它将检查我留下的值。我可以检查我喜欢的任何内容:及其输出:
It's much better to use something like the autovivification module to turn off that feature, or to use Data::Diver. However, this is one of the simple tasks that I'd expect a programmer to know how to do on his own. Even if you don't use this technique here, you should know it for other problems. This is essentially what
Data::Diver
is doing once you strip away its interface.This is easy once you get the trick of walking a data structure (if you don't want to use a module that does it for you). In my example, I create a
check_hash
subroutine that takes a hash reference and an array reference of keys to check. It checks one level at a time. If the key is not there, it returns nothing. If the key is there, it prunes the hash to just that part of the path and tries again with the next key. The trick is that$hash
is always the next part of the tree to check. I put theexists
in aneval
in case the next level isn't a hash reference. The trick is not to fail if the hash value at the end of the path is some sort of false value. Here's the important part of the task:Don't be scared by all the code in the next bit. The important part is just the
check_hash
subroutine. Everything else is testing and demonstration:Here's the output (minus the data dump):
Now, you might want to have some other check instead of
exists
. Maybe you want to check that the value at the chosen path is true, or a string, or another hash reference, or whatever. That's just a matter of supplying the right check once you have verified that the path exists. In this example, I pass a subroutine reference that will check the value I left off with. I can check for anything I like:And its output:
您可以使用 autovivification 编译指示来停用引用的自动创建:
它也是词汇的,这意味着它只会在您指定的范围内停用它。
You could use the autovivification pragma to deactivate the automatic creation of references:
It's also lexical, meaning it'll only deactivate it inside the scope you specify it in.
在查看顶层之前检查每个级别是否存在。
如果您觉得这很烦人,您可以随时查看 CPAN。例如,有
Hash::NoVivify
。Check every level for
exist
ence before looking at the top level.If you find that annoying you could always look on CPAN. For instance, there is
Hash::NoVivify
.查看 Data::Diver。例如:
Take a look at Data::Diver. E.g.:
相当丑陋,但如果 $ref 是一个复杂的表达式,您不想在重复的存在测试中使用:
Pretty ugly, but if $ref is a complicated expression that you don't want to use in repeated exists tests: