Checking for existence of hash key creates key

2019-01-25 14:28发布

Given the following code

#!/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);

I have an empty hash that is created. I have an array with a few abbreviations in it. If I cycle through the array to see if these guys are in the hash, nothing is displayed to STDOUT which is expected but the $hash{output} is created for some reason. This does not make sense. All I am doing is an if exists. Where did I go wrong?

标签: perl hash
4条回答
地球回转人心会变
2楼-- · 2019-01-25 14:53

You've already got a couple good answers, but, if you want to read more about this behavior, it's normally called "autovivification" and there is a CPAN module available to disable it if you would prefer that it doesn't happen.

查看更多
仙女界的扛把子
3楼-- · 2019-01-25 14:58

exists looks for a hash element in a given hash. Your code is autogenerating the hash
%{ $hash{output} } and checking if a hash element with key $colo is existing in that hash.

Try the following:

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

changed to

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

You can, of course, write a sub that is hiding that complexity from your code.

查看更多
萌系小妹纸
4楼-- · 2019-01-25 15:01

The actual code/hash is more complexed. The hash is: $rotation_hash{output}{oor}{$colo}{$type}{$hostname}{file}{$filename} = <html_status_code>

As others have stated, when you ask about the existence of $foo{bar}{fubar}, Perl automatically creates $foo{bar} in order to test whether $foo{bar}{fubar} exists. If you want to prevent this, you have to test to see if $foo{bar} exists, and if it does, then test if $foo{bar}{fubar} exists.

However, what caught my eye was your seven layer hash. When your data structures start to get that complex, you should really be using Perl Object Oriented coding. I know a lot of people are scared off by Perl objected oriented programming, but Perl is probably one of the easiest languages for people in picking up OOP.

If for nothing else, you use OOP for the same reason you use use strict;. When I use strict;, Perl will easily pickup where I used $foobar as a variable in one place, but then refer to it as $fubar in another place. You lose that protection with complex data structures. For example, you might put $rotation_hash{output}{oor} in one place, but $rotation_hash{oor}{output} in another place, and use strict won't catch that. But, if you declare objects via package, and use subroutines as methods and constructors, you gain that back.

Object oriented design will also help you eliminate the need to track your data structure. The objects handle these for you, and you can concentrate on your coding. And, you don't have to create multiple files. You can simply attach the object definitions on the bottom of your file.

There are some excellent tutorials included in the Perl documentation. If you're not familiar with OOP Perl, you should go through the tutorials and give it a try.

查看更多
ゆ 、 Hurt°
5楼-- · 2019-01-25 15:04

Perl creates it because exists tests the last key specified, it doesn't test recursively. It should not get created if you instead do:

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

However why do you need the additional key at all? Why not just $hash{$colo}? Also if you If you use strict you'd get a warning about an uninitialized value in $hash.

查看更多
登录 后发表回答