Reputation: 3543
Is it possible to define anonymous subroutines in a hash constructor in Perl?
I'm trying to do something like this:
my %array = { one => sub { print "first $_[0]" },
two => sub { print "next $_[0]" },
three => sub { print "last $_[0]" }};
$array{$foo}->('thing');
But it isn't working. The code seems to run and compile, but the values in the array are blank. If I do this:
my %array;
$array{'one'} = sub { print "first $_[0]" };
$array{'two'} = sub { print "next $_[0]" };
$array{'three'} = sub { print "last $_[0]" };
$array{$foo}->('thing');
Then it seems to work fine. So I have a workaround, but it's just bugging me and I wondered if anyone knows whether it's possible and, if so, what the syntax is.
Upvotes: 1
Views: 1393
Reputation: 27234
Greg Hewgill is on the right track. Always enable the strict
pragma. Also, always enable warnings--but I recommend against using the -w switch in your code.
Instead, take advantage of the use warnings
pragma. That way you can selectively disable particular groups of warnings in lexically scoped areas of your code.
For example:
use strict;
use warnings;
foo('bar');
foo();
sub foo {
no warnings 'uninitialized';
my $foo = shift || 'DEFAULT';
print "Foo is $foo\n";
}
Consistent use of the strict and warnings pragmas will save you hours and hours of time.
Upvotes: 4
Reputation: 994887
I spent something like two hours trying to track down this exact braces-vs-parentheses problem in a script not too long ago. If you use the -w
switch to Perl, then you'll get a warning "Reference found where even-sized list expected", which at least gives a clue where to look. Today, all Perl scripts should start with:
#!/usr/bin/perl -w
use strict;
Your Perl life will be immeasurably less frustrating.
Upvotes: 3
Reputation: 1280
It's supposed to be parenthesis, not curly braces:
my %array = ( one => sub { print "first $_[0]" },
two => sub { print "next $_[0]" },
three => sub { print "last $_[0]" }});
'{ a => 1, b => 2 }' produces a reference to a hash. So the following would also work:
my $array = { one => sub { print "first $_[0]" },
two => sub { print "next $_[0]" },
three => sub { print "last $_[0]" }};
$array->{one}->('thing');
Upvotes: 2
Reputation: 110539
It looks like you're assigning into the hash incorrectly. Using {}
constructs an anonymous hash reference, which you assign to a scalar. But you're assigning to a named hash (%array
).
You need to assign into a scalar:
my $array = { one => sub { print "first $_[0]" },
two => sub { print "next $_[0]" },
three => sub { print "last $_[0]" }};
$array->{$foo}->('thing');
Or to not use the anon constructor syntax:
my %array = ( one => sub { print "first $_[0]" },
two => sub { print "next $_[0]" },
three => sub { print "last $_[0]" });
$array{$foo}->('thing');
Upvotes: 11
Reputation: 73762
That's because in the first case, you're creating a hashref not a hash, what you want is:
my $array;
$array = { one => ... }; # not %array = { .. };
...
$array->{one}->('thing');
Upvotes: 6