Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: Hash values change after returning from a subroutine

I'm working with hashes in perl, but don't understand why the hash value changes in the following:

use strict;

sub test
{
    my ($value_ref) = @_;
    my %value = %$value_ref;
    $value{'abc'}{'xyz'} = 1;
}

my %hash;
$hash{'abc'}{'xyz'} = 0;
test (\%hash);
print "$hash{'abc'}{'xyz'}\n";

The above returns 1, why doesn't it return 0 like this it does here?

use strict;

sub test
{
    my ($value_ref) = @_;
    my %value = %$value_ref;
    $value{'abc'} = 1;
}

my %hash;
$hash{'abc'} = 0;
test (\%hash);
print "$hash{'abc'}\n";

I imagine it has to do with how I'm passing in %hash. What am I missing?

like image 903
Laharl Avatar asked Nov 08 '13 18:11

Laharl


People also ask

How do I return a subroutine hash in Perl?

For this, you use -> and either [] to tell Perl you want to access a list element, or {} to tell Perl you want to access a hash element: $scalar = $ref->[ 1 ]; $scalar = $ref->{ name1 }; NOTICE: you're accessing one element, so you use the $ sign.

How does Perl store data in hash?

Perl for Beginners: Learn A to Z of Perl Scripting Hands-on A hash is a set of key/value pairs. Hash variables are preceded by a percent (%) sign. To refer to a single element of a hash, you will use the hash variable name preceded by a "$" sign and followed by the "key" associated with the value in curly brackets..

How do I reverse a hash in Perl?

%nhash = reverse %hash; Note that with reverse, duplicate values will be overwritten. the reverse way is nice, but it has some cavets (pasted directly from the perl docs): If a value is duplicated in the original hash, only one of those can be represented as a key in the inverted hash.

Is hash empty Perl?

From perldoc perldata: If you evaluate a hash in scalar context, it returns false if the hash is empty. If there are any key/value pairs, it returns true; more precisely, the value returned is a string consisting of the number of used buckets and the number of allocated buckets, separated by a slash.


1 Answers

You are getting incorrect results because when you make your copy of the hash using my %value = %$value_ref; you are only getting the top-level keys. The second level, with the key 'xyz', is the one where value is actually stored so any changes to that reference are carried over. You are performing a shallow copy when you need a deep copy.

Luckily there is a CPAN module for that!

use strict;
use Storable qw(dclone);

sub test
{
    my ($value_ref) = @_;
    my %value = %{ dclone($value_ref) };
    $value{'abc'}{'xyz'} = 1;
}

my %hash;
$hash{'abc'}{'xyz'} = 0;
test (\%hash);
print "$hash{'abc'}{'xyz'}\n"; # prints 0
like image 103
Hunter McMillen Avatar answered Sep 19 '22 23:09

Hunter McMillen