Je conserve le nom du sous-programme que je souhaite appeler au moment de l'exécution dans une variable appelée $ action. Ensuite, je l’utilise pour appeler ce sous-marin au bon moment:
&{\&{$action}}();
Fonctionne bien. La seule chose que je n'aime pas, c'est que c'est moche et 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 une façon plus jolie de le faire?
MISE À JOUR: L'idée ici était d'éviter de devoir maintenir une table de répartition chaque fois que j'ajoutais un nouveau sous-appelant, étant donné que je suis le seul développeur, je ne m'inquiète pas de ce que les autres programmeurs respectent ou ne respectent pas les règles. Sacrifier un peu de sécurité pour ma commodité. Au lieu de cela, mon module de dispatch vérifie $ action pour s'assurer que 1) c'est le nom d'un sous-programme défini et non pas du code malveillant à exécuter avec eval, et 2) qu'il ne lancerait aucun sous-répertoire précédé d'un trait de soulignement, ce qui serait: marqués comme internes uniquement par cette convention de nommage.
Des idées sur cette approche? J'oublierai tout le temps les sous-routines en liste blanche dans la table de répartition, et mes clients préfèrent que je me trompe du côté de "ça marche" que de "c'est méchant en sécurité". (temps très limité pour développer des applications)
FINAL UPDATE: Je pense avoir choisi une table de répartition après tout. Bien que je sois curieux de savoir si quelqu'un qui lit cette question a déjà essayé d'en éliminer une et comment il l'a fait, je dois m'incliner devant la sagesse collective. Merci à tous, beaucoup de bonnes réponses.
Plutôt que de stocker les noms de sous-routines dans une variable et de les appeler, une meilleure méthode consiste à utiliser un hachage de références de sous-routines (autrement appelé table dispatch .)
my %actions = ( foo => \&foo,
bar => \&bar,
baz => sub { print 'baz!' }
...
);
Ensuite, vous pouvez appeler le bon facilement:
$actions{$action}->();
Vous pouvez également ajouter des vérifications pour vous assurer que $action
est une clé valide dans le hachage, etc.
En général, évitez les références symboliques (ce que vous êtes en train de faire) car elles causent toutes sortes de problèmes. De plus, l’utilisation de véritables références de sous-programmes fonctionnera avec strict
activé.
Juste &$action()
, mais il est généralement préférable d'utiliser coderefs depuis le début ou d'utiliser un hachage de répartiteur. Par exemple:
my $disp = {foo => \&some_sub, bar => \&some_other_sub };
$disp->{'foo'}->();
Hein? Tu peux juste dire
$action->()
Exemple:
sub f { return 11 }
$action = 'f';
print $action->();
$ Perl subfromscalar.pl
11
Des constructions comme
'f'->() # equivalent to &f()
aussi travailler.
Je ne suis pas sûr de comprendre ce que vous voulez dire. (Je pense que c'est un autre groupe récent de questions "Comment utiliser une variable comme nom de variable?", Mais peut-être pas.)
Dans tous les cas, vous devriez pouvoir affecter un sous-programme entier à une variable (en tant que référence), puis 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"
}
La chose la plus importante est: pourquoi voulez-vous utiliser la variable comme nom de fonction? Que se passera-t-il si ce sera 'eval'? Y a-t-il une liste de fonctions pouvant être utilisées? Ou peut-il être n'importe quelle fonction? Si la liste existe - quelle est sa durée?
Généralement, le meilleur moyen de gérer de tels 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' );
__PACKAGE__->can($action)->(@args);
Pour plus d'informations sur can (): http://perldoc.Perl.org/UNIVERSAL.html
Je fais quelque chose de similaire. Je l'ai divisé en deux lignes pour le rendre légèrement plus identifiable, mais ce n'est pas beaucoup plus joli.
my $sub = \&{$action};
$sub->();
Je ne connais pas de manière plus correcte ou plus jolie de le faire. Pour ce que cela vaut, nous avons un code de production qui fait ce que vous faites, et cela fonctionne sans avoir à désactiver use strict
.
Chaque paquet en Perl est déjà une table de hachage. Vous pouvez ajouter des éléments et les référencer par les opérations de hachage normales. En général, il n'est pas nécessaire de dupliquer la fonctionnalité par une table de hachage supplémentaire.
#! /usr/bin/Perl -T
use strict;
use warnings;
my $tag = 'HTML';
*::->{$tag} = sub { print '<html>', @_, '</html>', "\n" };
HTML("body1");
*::->{$tag}("body2");
Le code imprime:
<html> body1 </ html> <html> body2 </ html>
Si vous avez besoin d'un espace de nom séparé, vous pouvez définir un package dédié.
Voir perlmod pour plus d'informations.
Je l'ai fait de cette façon:
@func = qw(cpu mem net disk);
foreach my $item (@func){
$ret .= &$item(1);
}
Soit utiliser
&{\&{$action}}();
Ou utilisez eval pour exécuter la fonction:
eval("$action()");
J'ai utilisé ceci: cela fonctionne pour moi.
(\$action)->();
Ou vous pouvez utiliser 'do', assez similaire aux posts précédents:
$p = do { \&$conn;};
$p->();
Si ce n'est que dans un programme, écrivez une fonction qui appelle un sous-programme en utilisant un nom de variable et que vous ne devez documenter/excuser qu'une seule fois