I have a function that takes a variable and an associative array, but I can\'t seem to get them to pass right. I think this has something to do with function declarations, h
It looks like you should pass in a reference to a hash.
sub PrintAA
{
my $test = shift;
my $aa = shift;
if (ref($aa) != "HASH") { die "bad arg!" }
....
}
PrintAA($foo, \%bar);
The reason you can't do a
my %aa = shift;
is because Perl flattens all the arguments to a subroutine into one list, @_. Every element is copied, so passing in by reference avoids those copies as well.
All the other replies here so far seem rather complicated to me. When I write Perl function I usually "expand" all the passed arguments in the first line of the function.
sub someFunction {
my ( $arg1, $arg2, $arg3 ) = @_;
This is similar to other languages, where you declare functions as
... someFunction ( arg1, arg2, arg3 )
And if you do it that way and pass the hash as the last argument, you'll be fine without any tricks or special magic. E.g.:
sub testFunc {
my ( $string, %hash ) = @_;
print "$string $hash{'abc'} $hash{'efg'} $string\n";
}
my %testHash = (
'abc' => "Hello",
'efg' => "World"
);
testFunc('!!!', %testHash);
The output is as expected:
!!! Hello World !!!
This works becaus in Perl arguments are always passed as an array of scalar values and if you pass a hash, it's key value/pairs are added to that array. In the sample above, the arguments passed to the function as array (@_
) are in fact:
'!!!', 'abc', 'Hello', 'efg', 'World'
and '!!!' is simple assigned to %string
, while %hash
"swallows" all the other arguments, always interpreting one as a key and the next one as value (until all elements are used up).
You cannot pass multiple hashes that way and the hash cannot be the first argument, as otherwise it would swallow everything and leaves all other arguments unassigned.
Of course exactly the same works for array as a last argument. The only difference here is that arrays don't distinguish between keys and values, for them all arguments left over are values and just get pushed to the array.
Use the folowing sub to get hash or hashref - whatever passed :)
sub get_args { ref( $_[0] ) ? shift() : ( @_ % 2 ) ? {} : {@_}; }
sub PrintAA
{
my $test = shift;
my $aa = get_args(@_);;
#then
$aa->{somearg} #do something
$aa->{anotherearg} #do something
}
Call your function like this:
printAA($firstarg,somearg=>1, anotherarg=>2)
Or like this(no matter):
printAA($firstarg,{somearg=>1, anotherarg=>2})
Or even like this(no matter):
my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \PrintAA );
PrintAA("test", %hash);
Cheers!
As usual there are several ways. Here is what Perl Best Practices, that most revered of style pointers, has to say about passing parameters to functions:
Use a hash of named arguments for any subroutine that has more than three parameters
But since you have only two, you could get away ;) with passing them directly like this:
my $scalar = 5;
my %hash = (a => 1, b => 2, c => 3);
func($scalar, %hash)
And function is defined like this:
sub func {
my $scalar_var = shift;
my %hash_var = @_;
... Do something ...
}
It could be more useful if you could show some code.
Alternatively:
sub PrintAA
{
my $test = shift;
my %aa = @_;
print $test . "\n";
foreach (keys %aa)
{
print $_ . " : " . $aa{$_} . "\n";
$aa{$_} = $aa{$_} . "+";
}
}
The thing you're fundamentally missing is that an associative array isn't a single argument (though an associative array reference is, as in Paul Tomblin's answer).
Pass the reference instead of the hash itself. As in
PrintAA("abc", \%fooHash);
sub PrintAA
{
my $test = shift;
my $aaRef = shift;
print $test, "\n";
foreach (keys %{$aaRef})
{
print $_, " : ", $aaRef->{$_}, "\n";
}
}
See also perlfaq7: How can I pass/return a {Function, FileHandle, Array, Hash, Method, Regex}?