Fletcher Moore
Fletcher Moore

Reputation: 13804

How do I dereference this hash in perl?

#!/usr/bin/perl
use Data::Dumper;

sub giveMeARef {
    my %hash = %{$_[0]};

    print "arg: ", Dumper($_[0]);
    print "deref: ", Dumper(%hash);
}

my %hash = ( "a" => (1,2,3), "b" => (3,4,5));

giveMeARef(\%hash);

This produces the following output:

arg: $VAR1 = {
          '2' => 3,
          '4' => 5,
          'a' => 1,
          'b' => 3
        };
deref: $VAR1 = 'b';
$VAR2 = 3;
$VAR3 = '2';
$VAR4 = 3;
$VAR5 = 'a';
$VAR6 = 1;
$VAR7 = '4';
$VAR8 = 5;

I tried to follow the examples in How do I dereference a Perl hash reference that's been passed to a subroutine?

But I believe because my hash is more complicated, it isn't working out for me. How do I get back to the original structure I passed in?

Upvotes: 0

Views: 150

Answers (3)

thepace
thepace

Reputation: 2221

There are two issues here:

  • The way Dumper is used to print the hash without passing reference wherein it resolves to print all the elements as $VAR1, $VAR2, etc.

    Dumper(\%hash)

  • The way the hash is initialized. Since the value is a list, it should be initialized as

    my %hash = ( "a" => [1,2,3], "b" => [3,4,5]);

A more correct code.

#!/usr/bin/perl
use Data::Dumper;

sub giveMeARef {
    my %hash = %{$_[0]};

    print "arg: ", Dumper($_[0]); #Dumper is passed a Ref.
    print "deref: ", Dumper(\%hash); # Dumper should be called with a hash ref.
}

my %hash = ( "a" => [1,2,3], "b" => [3,4,5]);

giveMeARef(\%hash);

Upvotes: 1

Matt Jacob
Matt Jacob

Reputation: 6553

As I mentioned in my comment, you're flattening a list when you create %hash. The fat comma (=>) is a synonym for the comma that causes barewords on the left to be interpreted as strings, but it doesn't matter in this case because you've already got a string on the left. In effect, your hash assignment really looks like this:

my %hash = ("a", 1, 2, 3, "b", 3, 4, 5);

It looks like you were trying to assign arrays to a and b, but in Perl, hash values are always scalars, so you need to use references to anonymous arrays instead:

my %hash = (a => [1, 2, 3], b => [3, 4, 5]);

It's also worth noting that your subroutine is making a shallow copy of the hash reference you pass in, which may have unintended/unforeseen consequences. Consider the following:

use Data::Dump;

sub giveMeARef {
    my %hash = %{$_[0]};
    pop(@{$hash{a}});
}

my %hash = (a => [1, 2, 3], b => [3, 4, 5]);

dd(\%hash);
giveMeARef(\%hash);
dd(\%hash);

Which outputs:

{ a => [1, 2, 3], b => [3, 4, 5] }
{ a => [1, 2], b => [3, 4, 5] }

Upvotes: 6

Thilo
Thilo

Reputation: 262464

The code is fine, but your test hash is not what you think it is.

You cannot construct a hash like that. The lists in there got flattened out. You need to use array-refs instead:

my %hash = ( "a" => [1,2,3], "b" => [3,4,5]);

Since you are going to take a reference to that hash anyway, you might as well start there:

my $hash_ref = { a => [1,2,3], b => [3,4,5] };

Upvotes: 3

Related Questions