66 votes

Comment puis-je appeler de manière élégante une sous-routine Perl dont le nom est contenu dans une variable ?

Je conserve le nom de la sous-routine que je veux appeler au moment de l'exécution dans une variable appelée $action. Je l'utilise ensuite pour appeler cette sous-routine au bon moment :

&{\&{$action}}();

Fonctionne bien. La seule chose que je n'aime pas, c'est que c'est moche et qu'à chaque fois que je le fais, je me sens obligé d'ajouter un commentaire pour le prochain développeur :

# call the sub by the name of $action

Quelqu'un connaît-il un moyen plus joli de faire cela ?


MISE À JOUR : L'idée ici était d'éviter d'avoir à maintenir une table de répartition à chaque fois que j'ajoutais un nouveau sous-sujet appelable, puisque je suis le seul développeur, je ne m'inquiète pas du fait que les autres programmeurs suivent ou non les " règles ". Je sacrifie un peu de sécurité pour mon confort. Au lieu de cela, mon module de distribution vérifierait $action pour s'assurer que 1) c'est le nom d'une sous-routine définie et non du code malveillant à exécuter avec eval, et 2) qu'il n'exécuterait pas de sous-programme précédé d'un trait de soulignement, qui serait marqué comme sous-programme interne seulement par cette convention de nommage.

Que pensez-vous de cette approche ? J'oublie souvent de placer des sous-routines sur la liste blanche dans la table d'envoi, et mes clients préfèrent que je prenne le parti du "ça marche" plutôt que du "c'est méchamment sûr". (temps très limité pour développer des applications)


MISE À JOUR FINALE : Je pense que j'ai finalement opté pour une table d'expédition. Bien que je sois curieux de savoir si quelqu'un qui lit cette question a déjà essayé de s'en passer et comment il l'a fait, je dois m'incliner devant la sagesse collective ici. Merci à tous, beaucoup de bonnes réponses.

90voto

friedo Points 36209

Plutôt que de stocker les noms des sous-routines dans une variable et de les appeler, une meilleure façon de procéder est d'utiliser un hachage de références de sous-routines (autrement connu sous le nom de tableau de répartition .)

my %actions = ( foo => \&foo,
                bar => \&bar,
                baz => sub { print 'baz!' } 
                ... 
              );

Vous pourrez alors facilement appeler la bonne personne :

$actions{$action}->();

Vous pouvez également ajouter des vérifications pour vous assurer $action est une clé valide dans le hachage, et ainsi de suite.

En général, vous devriez éviter les références symboliques (ce que vous faites maintenant) car elles causent toutes sortes de problèmes. De plus, l'utilisation de références réelles de sous-routine fonctionnera avec strict tourné vers l'avenir.

22voto

Harmen Points 525

Juste &$action() mais il est généralement plus agréable d'utiliser des références de code dès le début, ou d'utiliser un hachage de répartiteur. Par exemple :

my $disp = {foo => \&some_sub, bar => \&some_other_sub };
$disp->{'foo'}->();

17voto

mob Points 61524

Hein ? Vous pouvez juste dire

    $action->()

Ejemplo:

    sub f { return 11 }
    $action = 'f';
    print $action->();

    $ perl subfromscalar.pl
    11

Des constructions comme

    'f'->()     # equivalent to   &f()

fonctionnent également.

12voto

Telemachus Points 12013

Je ne suis pas sûr de comprendre ce que vous voulez dire. (Je pense qu'il s'agit d'une autre question dans un groupe récent de questions "Comment puis-je utiliser une variable comme nom de variable ?", mais peut-être pas).

Dans tous les cas, vous devriez être en mesure d'affecter une sous-routine entière à une variable (en tant que référence), puis de l'appeler directement :

# create the $action variable - a reference to the subroutine
my $action = \&preach_it;
# later - perhaps much later - I call it
$action->();

sub preach_it {
    print "Can I get an amen!\n"
}

10voto

Le plus important est de savoir pourquoi vous voulez utiliser une variable comme nom de fonction. Que se passera-t-il s'il s'agit de 'eval' ? Existe-t-il une liste de fonctions qui peuvent être utilisées ? Ou est-ce que n'importe quelle fonction peut être utilisée ? Si la liste existe, quelle est sa longueur ?

En général, la meilleure façon de traiter ces cas est d'utiliser des tables de répartition :

my %dispatch = (
   'addition' => \&some_addition_function,
   'multiplication' => sub { $self->call_method( @_ ) },
);

Et puis juste :

$dispatch{ $your_variable }->( 'any', 'args' );

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X