2009-08-05 6 views
4

J'ai une liste de fonctions en Perl. Exemple:Comment puis-je faire défiler une liste de fonctions dans Perl?

my @funcs = qw (a b c) 

Maintenant, ils appartiennent tous à ce module Foo :: Bar :: Stix. Je voudrais les appeler itérativement dans une boucle:

foreach $func (@funcs) { 
    Foo::Bar::Stix::$func->(%args) 
} 

où args est un hachage d'arguments. Cependant, je continue d'obtenir cette erreur: "Bad name after :: ..." sur la ligne qui contient Foo :: Bar :: Stix :: $ func -> (% args) Comment corriger cette erreur?

a b et c ne sont pas des objets de fonction, mais les chaînes

Répondre

9

Plutôt que de stocker les noms des fonctions dans votre tableau, les références de magasin pour les dans un hachage de sorte que vous pouvez vous référer à eux par leur nom. Voici un exemple simple de code:

#!/usr/bin/perl 

use strict; 
use warnings; 

my %func_refs = (
    'a' => \&Foo::Bar::Stix::a, 
    'b' => \&Foo::Bar::Stix::b, 
    'c' => \&Foo::Bar::Stix::c 
); 

foreach my $func_ref (values %func_refs) { 
    print $func_ref->("woohoo: "), "\n"; 
} 

{ 
    package Foo::Bar::Stix; 

    sub a { 
    my $arg = shift; 
    return $arg . "a"; 
    } 

    sub b { 
    my $arg = shift; 
    return $arg . "b"; 
    } 

    sub c { 
    my $arg = shift; 
    return $arg . "c"; 
    } 
} 

Si vous êtes coincé avec le stockage des noms pour une raison quelconque, essayez ceci:

my $package = "Foo::Bar::Stix"; 
my @func_names = qw/ a b c /; 
foreach my $func_name (@func_names) { 
    my $str = &{ "$package\::$func_name" }("woohoo: "); 
    print $str, "\n"; 
} 

Cependant, cela ne fonctionne pas sous use strict, et à cause de cela Je préfère la première solution. Quoi que vous fassiez, essayez d'éviter d'utiliser eval. Ce n'est pas nécessaire, et ne vous causera probablement que des problèmes. En outre, la plupart des personnes qui utilisent Perl le mettent en majuscules comme Perl plutôt que PERL. Voici une question Stackoverflow sur le sujet:

How should I capitalize Perl?

+3

+1 pour lier à la question de capitalisation. Votre karma sera si mauvais que rien ne fonctionnera si vous pensez à Perl comme PERL. – innaM

+1

'$ Foo :: Bar :: Stix :: {$ func} -> (% args);' fonctionnerait aussi, et ne nécessite pas de désactiver strict. –

1

Léger changement de syntaxe vous donnera ce que vous voulez

Foo::Bar::Stix->$func(%args) 

Bien que cela passera le nom du package comme premier paramètre.

3

Mauvaise réponse: utiliser une référence symbolique:

for $func (@funcs) { 
    &{"Foo::Bar::Stix::$func"}(\%args); 
} 

Bonne réponse: utiliser une table d'expédition:

my %call_func = (
    'a' => \&Foo::Bar::Stix::a, 
    'b' => \&Foo::Bar::Stix::b, 
    'c' => \&Foo::Bar::Stix::c, 
); 
... 
for $func (@funcs) { 
    $call_func{$func}->(\%args); 
} 
+0

Je suis totalement d'accord avec vous, je l'ai dit la même chose dans ma réponse . –

0

Vous pouvez y accéder via la variable %Foo::Bar::Stix:: spéciale. Cela donne un accès complet directement à la table des symboles. Vous remarquerez également que cela fonctionne en mode strict.

#! /usr/bin/env perl 
use strict; 
use warnings; 

{ 
    package Foo::Bar::Stix; 
    sub a{ print "sub a\n" } 
    sub b{ print "sub b\n" } 
    sub c{ print "sub c\n" } 
} 

my @funcs = qw' a b c '; 
my %args; 

for my $func (@funcs) { 
    $Foo::Bar::Stix::{$func}->(%args); # <==== 
} 

Une autre option:

my $symbol_table = $::{'Foo::'}{'Bar::'}{'Stix::'}; 

my %funcs = (
    # we only want the CODE references 
    'a' => *{ $symbol_table->{'a'} }{'CODE'}, 
    'b' => *{ $symbol_table->{'b'} }{'CODE'}, 
    'c' => *{ $symbol_table->{'c'} }{'CODE'}, 
); 

for my $func (@funcs) { 
    $funcs{$func}->(%args); # <==== 
} 

Si vous allez faire que pour un grand nombre de sous-routines, voici comment je charger la variable %funcs.

my %funcs; 
BEGIN{ 
    my $symbol_table = $::{'Foo::'}{'Bar::'}{'Stix::'}; 

    for my $name (qw' a b c '){ 
    $funcs{$name} = *{ $symbol_table->{$name} }{'CODE'}; 
    } 
} 

Je ne ferais pas cela à moins que vous avez besoin des sous-routines d'avoir à la fois un nom complet et l'accès à travers une variable de hachage.

Si vous avez seulement besoin d'accéder aux sous-programmes via une variable de hachage, c'est une meilleure façon de le configurer.

my %funcs = (
    'a' => sub{ print "sub a\n" }, 
    'b' => sub{ print "sub b\n" }, 
    'c' => sub{ print "sub c\n" }, 
); 

Note: vous pouvez remplacer "my %funcs" par "our %funcs"

1

Vous pouvez utiliser can

my @funcs = qw (a b c) 
foreach $func (@funcs) { 
    Foo::Bar::Stix->can($func)->(%args) 
} 
+0

Je préfère utiliser 'qw 'a b c'' ou' qw "a b c" 'sur Stack Overflow, de sorte que la surbrillance soit plus raisonnable. –

Questions connexes