检查哈希键是否存在会创建键。

7

给定以下代码

#!/usr/bin/perl

use Data::Dumper;

my %hash;
my @colos = qw(ac4 ch1 ir2 ird kr3);

foreach my $colo (@colos) {
    if(exists $hash{output}{$colo}) {
        print "$colo is in the hash\n";
    }
}

print Dumper(\%hash);

我有一个空的哈希表,我创建了一个包含一些缩写的数组。如果我循环遍历数组来查看这些缩写是否在哈希表中,那么预期情况下不会在STDOUT中显示任何内容,但是一些原因导致$hash{output}被创建。这没有意义。我只是在做一个if exists。我错在哪里了?

4个回答

8

exists函数在给定的哈希表中查找哈希元素。您的代码正在自动生成哈希表%{ $hash{output} },并检查其中是否存在一个键为$colo的哈希元素。

请尝试以下操作:

if(exists $hash{output}{$colo}) {

改为

if(exists $hash{output} and exists $hash{output}{$colo}) {

当然,你可以编写一个子程序,将该复杂性隐藏在你的代码中。

3

Perl创建它是因为exists测试最后指定的键,而不是递归地测试。如果您改为执行以下操作,则不应创建它:

if( exists $hash{output} && exists $hash{output}{$colo} ) {

但你为什么需要额外的键呢?为什么不直接使用$hash{$colo}?并且,如果你使用use strict,你会得到一个关于在$hash中出现未初始化值的警告。


实际的代码/哈希更加复杂。哈希是:$rotation_hash {output} {oor} {$colo} {$type} {$hostname} {file} {$filename} = <html_status_code>。这是一个实用程序,可以扫描数千个主机并创建简要报告,告诉我哪些盒子已经超出了轮换范围。例如,它可能看起来像这样:$rotation_hash {output} {oor} {ac4} {www} {www10.foo.com} {files} {status.html} = 200。 - gdanko

3

你已经得到了一些不错的答案,但是如果你想更多地了解这种行为,它通常被称为“自动创建”(autovivification),并且有一个CPAN模块可用于禁用它,如果您希望它不发生。


2
实际的代码/哈希更为复杂。哈希值为:$rotation_hash {output} {oor} {$colo} {$type} {$hostname} {file} {$filename} = 。正如其他人所说,当你询问 $foo {bar} {fubar} 是否存在时,Perl 会自动创建 $foo {bar},以便测试 $foo {bar} {fubar} 是否存在。如果你想防止这种情况发生,你必须先测试 $foo {bar} 是否存在,如果存在,则再测试 $foo {bar} {fubar} 是否存在。然而,引起我的注意的是你的七层哈希。当你的数据结构变得如此复杂时,你应该真正使用 Perl 面向对象编程。我知道很多人对 Perl 面向对象编程感到害怕,但 Perl 可能是最容易让人们掌握 OOP 的语言之一。
如果不为其他原因,你使用面向对象编程(OOP)的原因与你使用use strict;的原因相同。当我使用use strict;时,Perl会轻松地发现我在一个地方将$foobar用作变量,但在另一个地方引用$fubar。对于复杂的数据结构,你会失去这种保护。例如,你可能会在一个地方放置$rotation_hash{output}{oor},而在另一个地方放置$rotation_hash{oor}{output}use strict不会捕捉到这一点。但是,如果通过package声明对象,并使用子例程作为方法和构造函数,你就可以重新获得这个保护。
面向对象设计还将帮助你消除跟踪数据结构的需要。对象会为你处理这些问题,你可以专注于编码。而且,你不必创建多个文件,只需将对象定义附加在文件底部即可。
在Perl文档中包含了一些优秀的教程。如果你不熟悉面向对象的Perl,你应该仔细阅读这些教程并尝试一下。其中sometutorials是可点击链接。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接