This is what I have:
use 5.14.0;
use strict;
use warnings;
sub my_func(&$) {
my $coderef = shift;
my %attribs = @_;
}
This is what I'd like to achieve:
my_func {
print 1;
} first_attrib => "1",second_attrib => "2";
However, I receive the error Too many arguments for main::my_func at x.pl line 12, near ""2";"
. How should I modify the prototype, so that the parameters after the coderef will be transformed into a hash?
If you change sub my_func(&$)
to sub my_func(&%)
your code will work.
The problem is that first_attrib => "1",second_attrib => "2"
isn't a hash ref, but a list. And as friedo pointed out a list can be assigned to a hash, though a list with an odd number of elements might produce unwanted results and will produce a warning with use warnings
.
Alternatively you can change your code to
sub my_func(&$) {
my $coderef = shift;
my ($attribs) = @_;
}
my_func {
print 1;
} {first_attrib => "1",second_attrib => "2"};
to achieve what you seem to want.
The reason why you must wrap $attribs
in parens is that assigning an array to a scalar returns just the number of elements in the array. At this point @_
is this array:
({first_attrib => "1",second_attrib => "2"})
with a hash ref as a single element.
($attribs) = @_;
tells perl to create an anonymous array with the scalar $attribs
as its first element, and assign elements from @_
to the anonymous array, element by element, thus making $attribs
point at the hash ref in @_
.
You need to realize the arguments to a Perl sub form a list. You use the first element of the argument list for the coderef and the remaining elements to form a hash:
#!/usr/bin/env perl
use 5.14.0;
use strict;
use warnings;
sub my_func(&@) {
my $coderef = shift;
my %attribs = @_;
$coderef->() for keys %attribs;
}
my_func {
print 1;
} first_attrib => "1",second_attrib => "2";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With