0

Here's my current thinking, but I dont know how to dispatch/execute it

my $key;
my @arraydata;

my %commandfunc{
"ab 1", \&func1(\@arraydata),
"ab 2", \&func2(\@arraydata,
"ab 3", \&func3(\@arraydata)
};

foreach $k (keys %commandfunc){
  if($something =~ /$k/){ #if $something match with a key string
        $key= $k;
        #some processing arraydata here;
    }

}
#dispatching??
my $command = $commandfunc{$key}->(\@arraydata);

Please correct my code.. Thanks alot

brian d foy
  • 129,424
  • 31
  • 207
  • 592
mhd
  • 4,561
  • 10
  • 37
  • 53
  • you should take a look at http://stackoverflow.com/questions/1281456/how-do-i-implement-dispatch-tables-in-perl –  Nov 23 '09 at 05:31

3 Answers3

6

Hashes are initialized with regular parens ( ( ) ), not curly brackets (those are for hash references.) And you initialize a hash with a list assignment. So the first part should be:

my %commandfunc = ( 
    "ab 1" => \&func1,
    "ab 2" => \&func2,
    "ab 3" => \&func3
);

The => operator is a little prettier than using a comma and has the added benefit of quoting barewords on the left side, if necessary.

I'm not sure what you're trying to match in your loop (where does $_ come from?) But you can do something like this:

foreach my $k (keys %commandfunc) {
    if( $something =~ /$k/) {
        my $result = $commandfunc{$k}->( \@arraydata );
    }
}
friedo
  • 65,762
  • 16
  • 114
  • 184
5

\&func1 is a subroutine reference, but \&func1(\@arraydata) is a reference to the value returned by a call to &func1. Try instead just: "ab 1" => \&func1, .... The passing of @arraydata is correct in your dispatch code.

Note that /$k/ will make metacharacters like . or * have their special effect in the regex; if you don't want that, do /\Q$k/ instead. Or possibly you want just eq $k?

ysth
  • 96,171
  • 6
  • 121
  • 214
4

You weren't really clear whether @arraydata was defined up front or not, and how often this code would be executed. A direct translation of your attempt would yield:

my %commandfunc = (
    "ab 1" => sub { func1(@arraydata) },
    "ab 2" => sub { func2(@arraydata) },
    "ab 3" => sub { func3(@arraydata) },
};

if (my ($match) = grep { $_ eq $key } keys %commandfunc)
{
    my $result = &{$commandfunc{$match}};
}

However this is not very efficient - the %commandfunc hash is being defined with anonymous subroutine closures, when we could instead just store coderefs to the original subs with no arguments bound, and pass in an array later:

my %commandfunc = (
    "ab 1" => \&func1,
    "ab 2" => \&func2,
    "ab 3" => \&func3,
};

and call it like this:

my $result = $commandfunc{$match}->(@array);
Ether
  • 53,118
  • 13
  • 86
  • 159
  • looking at mhd's code, I decided that since @arraydata was being passed at the time of dispatch, this couldn't be what he meant. – ysth Nov 23 '09 at 17:17
  • @ysth: aye, so making a table of simple coderefs would be more appropriate then. – Ether Nov 23 '09 at 17:48