Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I pass a hash to subroutine?

Need help figuring out how to do this. My code:

my %hash;
$hash{'1'}= {'Make' => 'Toyota','Color' => 'Red',};
$hash{'2'}= {'Make' => 'Ford','Color' => 'Blue',};
$hash{'3'}= {'Make' => 'Honda','Color' => 'Yellow',};


&printInfo(%hash);

sub printInfo{
   my (%hash) = %_;
   foreach my $key (keys %_{       
    my $a = $_{$key}{'Make'};   
    my $b = $_{$key}{'Color'};   
    print "$a $b\n";
    }
}
like image 664
masterial Avatar asked Feb 03 '11 23:02

masterial


3 Answers

The easy way, which may lead to problems when the code evolves, is simply by assigning the default array @_ (which contains all key-value-pairs as an even list) to the %hash which then rebuilds accordingliy. So your code would look like this:

sub printInfo {    my %hash = @_;    ... } 

The better way would be to pass the hash as reference to the subroutine. This way you could still pass more parameters to your subroutine.

printInfo(\%hash); sub PrintInfo {    my %hash = %{$_[0]};    ... } 

An introduction to using references in Perl can be found in the perlreftut

like image 170
Sven Eppler Avatar answered Sep 28 '22 10:09

Sven Eppler


You're so very, very close. There is no %_ for passing hashes, it must be passed in @_. Luckily, Hashes are assigned using a list context, so

sub printInfo {    my %hash = @_;    ... } 

will make it work!

Also note, using the & in front of the subroutine call has been, in most cases, unnecessary since at least Perl 5.000. You can call Perl subroutines just like in other languages these days, with just the name and arguments. (As @mob points out in the comments, there are some instances where this is still necessary; see perlsub to understand this more, if interested.)

like image 27
Robert P Avatar answered Sep 28 '22 12:09

Robert P


The best way to pass hashes and arrays is by reference. A reference is simply a way to talk about a complex data structure as a single data point -- something that can be stored in a scalar variable (like $foo).

Read up on references, so you understand how to create a reference and dereference a reference in order to get your original data back.

The very basics: You precede your data structure with a backslash to get the reference to that structure.

my $hash_ref   = \%hash;
my $array_ref  = \@array;
my $scalar_ref = \$scalar;   #Legal, but doesn't do much for you...

A reference is a memory location of the original structure (plus a clue about the structure):

print "$hash_ref\n";

Will print something like:

HASH(0x7f9b0a843708)

To get the reference back into a useable format, you simply put the reference into the correct sigil in front:

my %new_hash = %{ $hash_ref };

You should learn about using references since this is the way you can create extremely complex data structures in Perl, and how Object Oriented Perl works.


Let's say you want to pass three hashes to your subroutine. Here are the three hashes:

my %hash1 = ( this => 1, that => 2, the => 3, other => 4 );
my %hash2 = ( tom => 10, dick => 20, harry => 30 );
my %hash3 = ( no => 100, man => 200, is => 300, an => 400, island => 500 );

I'll create the references for them

my $hash_ref1 = \%hash1;
my $hash_ref2 = \%hash2;
my $hash_ref3 = \%hash3;

And now just pass the references:

mysub ( $hash_ref1, $hash_ref2, $hash_ref3 );

The references are scalar data, so there's no problem passing them to my subroutine:

sub mysub {
    my $sub_hash_ref1  = shift;
    my $sub_hash_ref2  = shift;
    my $sub_hash_ref3  = shift;

Now, I just dereference them, and my subroutine can use them.

    my %sub_hash1 = %{ $sub_hash_ref1 };
    my %sub_hash2 = %{ $sub_hash_ref2 };
    my %sub_hash3 = %{ $sub_hash_ref3 };

You can see what a reference is a reference to by using the ref command:

my $ref_type = ref $sub_hash_ref;    # $ref_type is now equal to "HASH"

This is useful if you want to make sure you're being passed the correct type of data structure.

sub mysub {
    my $hash_ref = shift;

    if ( ref $hash_ref ne "HASH" ) {
        croak qq(You need to pass in a hash reference);
    }

Also note that these are memory references, so modifying the reference will modify the original hash:

my %hash = (this => 1, is => 2, a => 3 test => 4);
print "$hash{test}\n";   # Printing "4" as expected
sub mysub ( \%hash );    # Passing the reference
print "$hash{test}\n";   # This is printing "foo". See subroutine:


sub mysub { 
    my $hash_ref = shift;

    $hash_ref->{test} = "foo";    This is modifying the original hash!
}

This can be good -- it allows you to modify data passed to the subroutine, or bad -- it allows you to unintentionally modify data passed to the original subroutine.

like image 26
David W. Avatar answered Sep 28 '22 11:09

David W.