26

I was asked to modify some existing code to add some additional functionality. I have searched on Google and cannot seem to find the answer. I have something to this effect...

%first_hash = gen_first_hash();
%second_hash = gen_second_hash();
do_stuff_with_hashes(%first_hash, %second_hash);

sub do_stuff_with_hashes
{
    my %first_hash = shift;
    my %second_hash = shift;

    # do stuff with the hashes
}

I am getting the following errors:

Odd number of elements in hash assignment at ./gen.pl line 85.
Odd number of elements in hash assignment at ./gen.pl line 86.
Use of uninitialized value in concatenation (.) or string at ./gen.pl line 124.
Use of uninitialized value in concatenation (.) or string at ./gen.pl line 143.

Line 85 and 86 are the first two lines in the sub routine and 124 and 143 are where I am accessing the hashes. When I look up those errors it seems to suggest that my hashes are uninitialized. However, I can verify that the hashes have values. Why am I getting these errors?

4

5 回答 5

27

The hashes are being collapsed into flat lists when you pass them into the function. So, when you shift off a value from the function's arguments, you're only getting one value. What you want to do is pass the hashes by reference.

do_stuff_with_hashes(\%first_hash, \%second_hash);

But then you have to work with the hashes as references.

my $first_hash  = shift;
my $second_hash = shift;
于 2009-07-21T18:56:15.750 回答
16

A bit late but,

As have been stated, you must pass references, not hashes.

do_stuff_with_hashes(\%first_hash, \%second_hash);

But if you need/want to use your hashes as so, you may dereference them imediatly.

sub do_stuff_with_hashes {
    my %first_hash = %{shift()};
    my %second_hash = %{shift()};
};
于 2009-07-27T14:49:43.600 回答
9

Hash references are the way to go, as the others have pointed out.

Providing another way to do this just for kicks...because who needs temp variables?

do_stuff_with_hashes( { gen_first_hash() }, { gen_second_hash() } );

Here you are just creating hash references on the fly (via the curly brackets around the function calls) to use in your do_stuff_with_hashes function. This is nothing special, the other methods are just as valid and probably more clear. This might help down the road if you see this activity in your travels as someone new to Perl.

于 2009-07-21T19:11:53.377 回答
7

First off,

 do_stuff_with_hashes(%first_hash, %second_hash);

"streams" the hashes into a list, equivalent to:

 ( 'key1_1', 'value1_1', ... , 'key1_n', 'value1_n', 'key2_1', 'value2_1', ... )

and then you select one and only one of those items. So,

 my %first_hash = shift;

is like saying:

 my %first_hash = 'key1_1'; 
 # leaving ( 'value1', ... , 'key1_n', 'value1_n', 'key2_1', 'value2_1', ... )

You cannot have a hash like { 'key1' }, since 'key1' is mapping to nothing.

于 2009-07-21T19:00:24.837 回答
0

A solution without shift() is faster, because it do not copy the data in memory, and you can modify the hash in the subroutine. See my example:

sub do_stuff_with_hashes($$$) {
    my ($str,$refHash1,$refHash2)=@_;
    foreach (keys %{$refHash1}) { print $_.' ' }
    $$refHash1{'new'}++;
}

my (%first_hash, %second_hash);
$first_hash{'first'}++;
do_stuff_with_hashes('any_parameter', \%first_hash, \%second_hash);
print "\n---\n", $first_hash{'new'};
于 2020-06-18T08:23:20.993 回答