Reputation: 139
I have the following code:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
my $site = "test.com";
my $data = {
"test" => 1
};
my $user = defined($data->{addons}->{$site}->{username}) ? $data->{addons}->{$site}->{username} : "nothing";
print Dumper($data);
The result:
$VAR1 = {
'test' => 1,
'addons' => {
'test.com' => {}
}
};
As you can see the check if the user is defined in the nested structure actually creates an empty keys. My questing is how to check the hashref without defining the keys.
Upvotes: 2
Views: 778
Reputation: 67918
As Dave Cross pointed out, this is autovivification. Normally, you do not need to worry about it, unless you at some point make assumptions based on the existence of this hash key, or if your data sets are so large as to require very careful memory regulation.
You can use the no autovivification
pragma, preferably in a limited lexical scope, such as this:
my $user;
{ # no autovivification is limited to this block
no autovivification;
$user = $data->{addon}{$site}{username} // "nothing";
}
//
is the defined-or operator, which is convenient to use in this case.
But for a simple problem like this, you might get away with a simpler solution:
my $user;
if ( defined $data->{addon}{$site} ) {
$user = $data->{addon}{$site}{username} // "nothing";
}
Upvotes: 1
Reputation: 69274
You're stumbling over "autovivification". Perl automatically creates intermediate levels in data structures that you try to access. You can see it in action here:
$ perl -MData::Dumper -E'if (!$foo->{bar}->{baz}){}; say Dumper $foo'
$VAR1 = {
'bar' => {}
};
In order to check whether $foo->{bar}->{baz}
was true, Perl created $foo->{bar}
. That makes it easy to create complex data structures, but can be problematic when querying them.
But look at this:
$ perl -M-autovivification -MData::Dumper -E'if (!$foo->{bar}->{baz}){}; say Dumper $foo'
$VAR1 = undef;
The autovivification pragma makes it easy to turn off autovivification in parts of your code. So just add:
no autovivification;
In the block of code that is causing the problems.
Update: There's also the manual approach, which involves checking each level of the data structure and stopping looking as soon as you find something that doesn't match what you're looking for:
$ perl -MData::Dumper -E'if ("HASH" eq ref $foo and exists $foo->{bar} and !$foo->{bar}->{baz}){}; say Dumper $foo'
$VAR1 = undef;
Upvotes: 3