web-dev-qa-db-fra.com

Quand dois-je utiliser le & pour appeler un sous-programme Perl?

J'ai entendu dire que les gens ne devraient pas utiliser & pour appeler les abonnés Perl, à savoir:

function($a,$b,...);
# opposed to
&function($a,$b,...);

Je sais que la liste d'arguments devient facultative, mais quels sont les cas où il est approprié d'utiliser le & et les cas où vous ne devriez absolument pas l'utiliser?

De même, comment l'augmentation de la performance entre-t-elle en jeu ici en omettant le &?

47
user105033

OMI, la seule fois où il y a une raison d'utiliser & Est si vous obtenez ou appelez un code de référence, comme:

sub foo() {
    print "hi\n";
}

my $x = \&foo;
&$x();

La principale fois que vous pouvez l'utilisez que vous ne devriez absolument pas dans la plupart des circonstances, c'est lorsque vous appelez un sous-marin qui a un prototype qui spécifie tout comportement d'appel non par défaut. Ce que je veux dire par là, c'est que certains prototypes permettent la réinterprétation de la liste d'arguments, par exemple la conversion des spécifications @array Et %hash En références. Ainsi, le sous-marin s'attendra à ce que ces réinterprétations se soient produites, et à moins que vous n'alliez à la longueur nécessaire pour les imiter à la main, le sous-marin recevra des entrées très différentes de celles qu'il attend.

Je pense que principalement les gens essaient de vous dire que vous écrivez toujours dans le style Perl 4, et nous avons maintenant une chose beaucoup plus propre et plus agréable appelée Perl 5.

En ce qui concerne les performances, Perl optimise les sous-appels de différentes manières que & Élimine, l'un des principaux étant l'inclusion de constantes.

Il existe également une circonstance où l'utilisation de & Offre un avantage en termes de performances: si vous transférez un appel secondaire avec foo(@_). L'utilisation de &foo Est infiniment plus rapide que foo(@_). Je ne le recommanderais pas à moins que vous n'ayez définitivement trouvé par profilage que vous avez besoin de cette micro-optimisation.

36
chaos

Je suis un abuseur fréquent de &, mais surtout parce que je fais des trucs d'interface bizarres. Si vous n'avez pas besoin de l'une de ces situations, n'utilisez pas le &. La plupart d'entre elles consistent simplement à accéder à une définition de sous-programme, et non à appeler un sous-programme. Tout est dans perlsub .

  1. Prendre une référence à un sous-programme nommé. C'est probablement la seule situation courante pour la plupart des Perlers:

     my $sub = \&foo;
    
  2. De même, l'affectation à un typeglob, qui vous permet d'appeler le sous-programme avec un nom différent:

     *bar = \&foo;
    
  3. Vérifier qu'un sous-programme est défini, comme vous le feriez dans les suites de tests:

     if( defined &foo ) { ... }
    
  4. Suppression d'une définition de sous-programme, qui ne devrait pas être courante:

     undef &foo;
    
  5. Fournir un sous-programme de répartiteur dont le seul travail consiste à choisir le bon sous-programme à appeler. C'est la seule situation que j'utilise & pour appeler un sous-programme, et quand je m'attends à appeler le répartiteur plusieurs fois et j'ai besoin de réduire un peu les performances de l'opération:

     sub figure_it_out_for_me {
        # all of these re-use the current @_
          if( ...some condition... ) { &foo     } 
       elsif( ...some other...     ) { &bar     }
       else                          { &default }
       }
    
  6. Pour sauter dans un autre sous-programme en utilisant la pile d'arguments en cours (et en remplaçant le sous-programme en cours dans la pile d'appels), une opération rare dans la répartition, en particulier dans AUTOLOAD:

     goto ⊂
    
  7. Appelez un sous-programme que vous avez nommé d'après un module Perl intégré. Le & vous donne toujours celui défini par l'utilisateur. C'est pourquoi nous l'enseignons dans Learning Perl . Vous ne voulez pas vraiment le faire normalement, mais c'est l'une des fonctionnalités de &.

Il existe des endroits où vous pouvez les utiliser, mais il existe de meilleures façons:

  1. Pour appeler un sous-programme portant le même nom qu'un module Perl intégré. N'ayez tout simplement pas de sous-programmes portant le même nom qu'un module Perl intégré. Cochez perlfunc pour voir la liste des noms intégrés que vous ne devez pas utiliser.

  2. Pour désactiver les prototypes. Si vous ne savez pas ce que cela signifie ou pourquoi vous le souhaitez, n'utilisez pas le &. Un code de magie noire pourrait en avoir besoin, mais dans ces cas, vous savez probablement ce que vous faites.

  3. Pour déréférencer et exécuter une référence de sous-routine. Utilisez simplement le -> notation.

52
brian d foy

Le formulaire & subroutine () désactive la vérification du prototype. Cela peut ou non être ce que vous voulez.

http://www.Perl.com/doc/manual/html/pod/perlsub.html#Prototypes

Les prototypes vous permettent de spécifier les nombres et les types de vos arguments de sous-programme, et de les faire vérifier au moment de la compilation. Cela peut fournir une assistance diagnostique utile.

Les prototypes ne s'appliquent pas aux appels de méthode ou aux appels effectués à l'ancienne en utilisant le préfixe &.

Le & est nécessaire pour référencer ou déréférencer un sous-programme ou une référence de code

par exemple.

sub foo {
   # a subroutine
}

my $subref = \&foo; # take a reference to the subroutine

&$subref(@args);  # make a subroutine call using the reference.

my $anon_func = sub { ... }; # anonymous code reference
&$anon_func(); # called like this

Les protypes ne s'appliquent pas non plus aux références de sous-programmes.

La forme & subroutine est également utilisée sous la forme dite magic goto .

L'expression goto &subroutine remplace le contexte d'appel actuel par un appel au sous-programme nommé, en utilisant la valeur actuelle de @_.

En substance, vous pouvez complètement basculer un appel vers un sous-programme avec un appel vers celui nommé. Cela se voit généralement dans les blocs AUTOLOAD, où un appel de sous-programme différé peut être effectué, peut-être avec quelques modifications à @_, mais il regarde le programme entièrement comme s'il s'agissait d'un appel au sous-nom nommé.

par exemple.

sub AUTOLOAD {
    ...
    Push @_, @extra_args; # add more arguments onto the parameter list
    goto &subroutine ; # change call another subroutine, as if we were never here
}

}

Cela pourrait être utile pour élimination des appels de queue , je suppose.

voir explication détaillée de cette technique ici

18
cms

J'ai lu les arguments contre l'utilisation de "&", mais je l'utilise presque toujours. Cela me fait gagner trop de temps pour ne pas le faire. Je passe une très grande partie de mon temps de codage Perl à rechercher quelles parties du code appellent une fonction particulière. Avec un &, je peux les rechercher et les trouver instantanément. Sans un & principal, j'obtiens la définition de la fonction, les commentaires et les instructions de débogage, triplant généralement la quantité de code que je dois inspecter pour trouver ce que je recherche.

La principale chose que vous n'utilisez pas "&" vous permet d'acheter des prototypes de fonctions. Mais les prototypes de fonction Perl peuvent créer des erreurs aussi souvent qu'ils les empêchent, car ils prendront votre liste d'arguments et la réinterpréteront de manière inattendue, de sorte que votre appel de fonction ne transmet plus les arguments qu'il dit littéralement.

1
Phil Goetz