10
votes

Comment @_ travaille-t-il dans les sous-programmes Perl?

J'étais toujours sûr que si je passais un sous-programme Perl un scalaire simple, il ne peut jamais changer sa valeur en dehors du sous-programme. C'est: xxx

donc si je veux foo () pour changer x , je dois transmettre une référence à x .

Puis j'ai découvert ce n'est pas le cas: xxx

et le même va pour les éléments de tableau: < Pré> xxx

qui m'a surpris. Comment cela marche-t-il? Le sous-programme ne fait-il que la valeur de l'argument? Comment connaissez-t-il son adresse?


4 commentaires

Perl n'est pas C. Ne vous attendez pas à ce qu'il se comporte comme c, ou tout langage dérivé C tel que C ++ ou Java.


Perldoc Perlsub


Votre question concerne @_ , pas $ _ . Et @_ dans un sous contient souvent des alias plutôt que des copies de valeurs. Donc, si vous ne voulez pas ce comportement dans votre sous , assurez-vous de copier l'entrée de @_ à Mes variables au début.


Je suis assez certain que cela est très bien documenté.


3 Réponses :



11
votes

Ceci est tout documenté en détail dans Perldoc Perlsub . Par exemple:

Tous arguments sont passés dans le tableau @_. Par conséquent, si vous appelez une fonction avec deux arguments, ceux-ci seraient stockés en $ _ [0] et $ _ [1]. Les Array @_ est un tableau local, mais ses éléments sont des alias pour les paramètres scalaires réels . En particulier, si un élément $ _ [0] est mis à jour, le L'argument correspondant est mis à jour (ou une erreur se produit s'il n'est pas mis à jour) . Si un argument est un élément ou un élément de hachage qui n'existait pas quand le La fonction a été appelée, cet élément n'est créé que lorsque (et si) il est modifié ou une référence à celle-ci est prise. (Certaines versions antérieures de Perl ont créé le élément si l'élément a été attribué ou non.) L'attribution à l'ensemble de la matrice @_ supprime que l'aliasing et ne met pas à jour les arguments.


1 commentaires

Quelqu'un devrait mentionner que l'aliasing est transitif, par exemple avec pour (@_) {s / ^ \ s + //; S / \ S + $ //} .



19
votes

en Perl, les arguments de sous-programme stockés dans @_ sont toujours des alias sur les valeurs sur le site d'appel. Cet aliasing ne persiste uniquement dans @_ si vous copiez des valeurs, c'est ce que vous obtenez, des valeurs.

donc dans ce sous: xxx

Notez que cet aliasing se produit après l'expansion de la liste, de sorte que si vous avez passé une matrice à Exemple , le tableau élargit dans le contexte de la liste et @_ est défini sur des alias de chaque élément. de la matrice (mais le tableau lui-même n'est pas disponible pour exemple ). Si vous vouliez ce dernier, vous vous référez à la matrice.

aliasing des arguments de sous-programme est une fonctionnalité très utile, mais doit être utilisée avec soin. Pour éviter la modification inattendue des variables externes, vous devez spécifier que vous souhaitez que vous souhaitiez des arguments aliasés appelés avec rw .

L'un des astuces moins connues mais utiles est d'utiliser cette Fonction d'aliasing permettant de créer des refures de réseau d'alias xxx

ou des tranches aliasées: xxx

Il s'avère également que l'utilisation de SUB {@__} -> (Liste) Pour créer un tableau à partir d'une liste est en réalité plus rapide que [Liste] car PERL n'a pas besoin de copier chaque valeur. Bien entendu, l'inconvénient (ou en fonction de votre perspective) est que les valeurs restent aliasées, vous ne pouvez donc pas les changer sans changer les originaux.

comme tchrist mentionne dans un Commentaire à une autre réponse, lorsque vous utilisez l'une des constructions d'aliasing de Perl sur @_ , le $ _ qu'ils vous fournissent sont également un alias aux arguments de sous-programme d'origine. Tels que: xxx

enfin tout ce comportement est contestable, donc lorsque vous utilisez @_ (ou une tranche de celui-ci) dans la liste des arguments de Un autre sous-programme, il reçoit également des alias aux premiers arguments du sous-programme: xxx


0 commentaires