web-dev-qa-db-fra.com

Quelle est la différence entre mon et local en Perl?

Je vois les deux utilisés dans ce script que j'essaie de déboguer et la littérature n'est tout simplement pas claire. Quelqu'un peut-il démystifier cela pour moi?

60
Brian G

Portée dynamique. C'est un concept soigné. Beaucoup de gens ne l'utilisent pas ou ne le comprennent pas.

Pensez essentiellement à my comme créant et ancrant une variable à un bloc de {}, A.K.A. portée.

my $foo if (true); # $foo lives and dies within the if statement.

Donc, une variable my est ce à quoi vous êtes habitué. alors qu'avec la portée dynamique, $ var peut être déclaré n'importe où et utilisé n'importe où. Ainsi, avec local, vous suspendez essentiellement l'utilisation de cette variable globale et utilisez une "valeur locale" pour travailler avec. Ainsi, local crée une portée temporaire pour une variable temporaire.

$var = 4;
print $var, "\n";
&hello;
print $var, "\n";

# subroutines
sub hello {
     local $var = 10;
     print $var, "\n";
     &gogo; # calling subroutine gogo
     print $var, "\n";
}
sub gogo {
     $var ++;
}

Cela devrait imprimer:

4
10
11
4
36
J.J.

La réponse courte est que my marque une variable comme privée dans une portée lexicale et local marque une variable comme privée dans une portée dynamique.

Il est plus facile de comprendre my, car cela crée une variable locale au sens habituel. Une nouvelle variable est créée et elle n'est accessible que dans le bloc lexical englobant, qui est généralement marqué par des accolades. Il existe quelques exceptions à la règle d'accolade, telles que:

foreach my $x (@foo) { print "$x\n"; }

Mais c'est juste Perl qui fait ce que tu veux dire. Normalement, vous avez quelque chose comme ça:

sub Foo {
   my $x = shift;

   print "$x\n";
}

Dans ce cas, $x est privé du sous-programme et sa portée est entourée par les accolades. La chose à noter, et c'est le contraste avec local, c'est que la portée d'une variable my est définie par rapport à votre code tel qu'il est écrit dans le fichier. C'est un phénomène au moment de la compilation.

Pour comprendre local, vous devez penser en termes de pile d'appel de votre programme pendant son exécution. Lorsqu'une variable est local, elle est redéfinie à partir du moment où l'instruction local s'exécute pour tout ce qui se trouve en dessous de celle sur la pile, jusqu'à ce que vous retourniez sauvegarder la pile à l'appelant du bloc contenant le local.

Cela peut être déroutant au début, alors considérez l'exemple suivant.

sub foo { print "$x\n"; }
sub bar { local $x; $x = 2; foo(); }

$x = 1;
foo(); # prints '1'
bar(); # prints '2' because $x was localed in bar
foo(); # prints '1' again because local from foo is no longer in effect

Lorsque foo est appelé la première fois, il voit la valeur globale de $x qui est 1. Lorsque bar est appelé et local $x s'exécute, ce qui redéfinit le global $x sur la pile. Maintenant, lorsque foo est appelé depuis bar, il voit la nouvelle valeur de 2 pour $x. Jusqu'à présent, ce n'est pas très spécial, car la même chose se serait produite sans l'appel à local. La magie est que lorsque bar revient, nous quittons la portée dynamique créée par local $x et le précédent global $x revient dans le champ d'application. Donc, pour l'appel final de foo, $x est égal à 1.

Vous voudrez presque toujours utiliser my, car cela vous donne la variable locale que vous recherchez. Une fois dans une lune bleue, local est vraiment pratique pour faire des choses sympas.

54
Jeremy Bourque

Citant de Learning Perl :

Mais local est mal nommé, ou du moins trompeusement nommé. Notre ami Chip Salzenberg dit que s'il avait la chance de remonter dans une machine à remonter le temps jusqu'en 1986 et de donner un conseil à Larry, il dirait à Larry d'appeler local par le nom "save" à la place. [14] C'est parce que local sauvera la valeur de la variable globale donnée, il sera donc automatiquement restauré plus tard dans la variable globale. (C'est vrai: ces variables dites "locales" sont en fait des globales!) Ce mécanisme de sauvegarde et de restauration est le même que nous avons déjà vu deux fois maintenant, dans la variable de contrôle d'une boucle foreach, et dans le @_ tableau de paramètres de sous-programme.

Ainsi, local enregistre la valeur actuelle d'une variable globale, puis la définit sur une forme de valeur vide. Vous verrez souvent qu'il est utilisé pour Slurper un fichier entier, plutôt que de commencer juste une ligne:

my $file_content;
{
    local $/;
    open IN, "foo.txt";
    $file_content = <IN>;
} 

Appeler local $/ définit le séparateur d'enregistrements d'entrée (la valeur à laquelle Perl arrête de lire une "ligne") sur une valeur vide, ce qui oblige l'opérateur du vaisseau spatial à lire l'intégralité du fichier, de sorte qu'il ne frappe jamais le séparateur d'enregistrements d'entrée.

19
Drew Stephens

Je ne peux pas croire que personne ne soit lié aux traités exhaustifs de Mark Jason Dominus sur la question:

16
Aristotle Pagaltzis

http://perldoc.Perl.org/perlsub.html#Private-Variables-via-my ()

Contrairement aux variables dynamiques créées par l'opérateur local, les variables lexicales déclarées avec my sont totalement cachées du monde extérieur, y compris les sous-programmes appelés. Cela est vrai s'il s'agit du même sous-programme appelé depuis lui-même ou ailleurs - chaque appel obtient sa propre copie.

http://perldoc.Perl.org/perlsub.html#Temporary-Values-via-local ()

Un local modifie ses variables listées pour être "local" au bloc englobant, eval, ou faire FILE - et à tout sous-programme appelé depuis ce bloc. Un local donne juste des valeurs temporaires aux variables globales (signifiant package). Il ne crée pas de variable locale. C'est ce que l'on appelle la portée dynamique. La portée lexicale est effectuée avec my, qui fonctionne plus comme les déclarations automatiques de C.

Je ne pense pas que cela ne soit pas du tout clair, sauf pour dire que par "local au bloc englobant", cela signifie que la valeur d'origine est restaurée lorsque le bloc est quitté.

9
Steve Jessop

Eh bien, Google fonctionne vraiment pour vous sur celui-ci: http://www.perlmonks.org/?node_id=94007

Depuis le lien:

Résumé rapide: "mon" crée une nouvelle variable, "local" modifie temporairement la valeur d'une variable.

c'est-à-dire que "local" modifie temporairement la valeur de la variable , mais seulement dans la portée il existe en.

Utilisez généralement mon, c'est plus rapide et ne fait rien de bizarre.

7
dlamblin

De man perlsub:

Contrairement aux variables dynamiques créées par l'opérateur local, les variables lexicales déclarées avec my sont totalement cachées du monde extérieur, y compris tout sous-programme appelé.

Donc, en simplifiant trop, my rend votre variable visible uniquement là où elle est déclarée. local le rend également visible dans la pile des appels. Vous souhaiterez généralement utiliser my au lieu de local.

6
catfood

Votre confusion est compréhensible. La portée lexicale est assez facile à comprendre, mais la portée dynamique est un concept inhabituel. La situation est aggravée par le fait que les noms my et local sont quelque peu inexacts (ou du moins peu intuitifs) pour des raisons historiques.

my déclare une variable lexicale - visible du point de déclaration jusqu'à la fin du bloc (ou fichier) englobant. Il est complètement indépendant de toute autre variable portant le même nom dans le reste du programme. Il est privé de ce bloc.

local, en revanche, déclare une modification temporaire de la valeur d'une variable globale. Le changement se termine à la fin de la portée englobante, mais la variable - étant globale - est visible n'importe où dans le programme.

En règle générale, utilisez my pour déclarer vos propres variables et local pour contrôler l'impact des modifications apportées aux variables intégrées de Perl.

Pour une description plus approfondie, voir l'article de Mark Jason Dominus Coping with Scoping .

4
Michael Carman

local est une méthode de localisation plus ancienne, datant de l'époque où Perl n'avait qu'une portée dynamique. La portée lexicale est beaucoup plus naturelle pour le programmeur et beaucoup plus sûre dans de nombreuses situations. mes variables appartiennent à la portée (bloc, package ou fichier) dans laquelle elles sont déclarées.

les variables locales appartiennent en fait à un espace de noms global. Si vous faites référence à une variable $ x avec local, vous faites en fait référence à $ main :: x, qui est une variable globale. Contrairement à ce que son nom l'indique, tout ce que local fait est de pousser une nouvelle valeur sur une pile de valeurs pour $ main :: x jusqu'à la fin de ce bloc, moment auquel l'ancienne valeur sera restaurée. C'est une fonctionnalité utile en soi, mais ce n'est pas un bon moyen d'avoir des variables locales pour une multitude de raisons (pensez à ce qui se passe lorsque vous avez des threads! Et pensez à ce qui se passe lorsque vous appelez une routine qui veut véritablement utiliser un global qui vous avez localisé!). Cependant, c'était le seul moyen d'avoir des variables qui ressemblaient à des variables locales dans le mauvais vieux temps avant Perl 5. Nous sommes toujours coincés avec cela.

3
skiphoppy

Regardez le code suivant et sa sortie pour comprendre la différence.

our $name = "Abhishek";

sub sub1
{
    print "\nName = $name\n";
    local $name = "Abhijeet";

    &sub2;
    &sub3;
}

sub sub2
{
    print "\nName = $name\n";
}

sub sub3
{
    my $name = "Abhinav";
    print "\nName = $name\n";
}


&sub1;

La sortie est:

Name = Abhishek

Name = Abhijeet

Name = Abhinav
2
Abhishek Kulkarni

"mes" variables sont visibles uniquement dans le bloc de code actuel. Les variables "locales" sont également visibles là où elles étaient auparavant visibles. Par exemple, si vous dites "my $ x;" et appeler une sous-fonction, il ne peut pas voir cette variable $ x. Mais si vous dites "local $ /;" (pour annuler la valeur du séparateur d'enregistrements), vous modifiez la façon dont la lecture à partir des fichiers fonctionne dans toutes les fonctions que vous appelez.

En pratique, vous voulez presque toujours "mon", pas "local".

2
andy
&s;

sub s()
{
    local $s="5";
    &b;
    print $s;
}

sub b()
{
    $s++;
}

Le script ci-dessus s'imprime 6.

Mais si nous changeons de local en my, il imprimera 5.

Voilà la différence. Facile.

0
Saravanarajan

Je pense que la façon la plus simple de s'en souvenir est la suivante. MY crée une nouvelle variable. LOCAL modifie temporairement la valeur d'une variable existante.

0
Hawk

l'exemple de dinomite d'utiliser local pour redéfinir le délimiteur d'enregistrement est la seule fois où j'ai rencontré beaucoup de programmation Perl. Je vis dans un environnement de niche Perl [programmation de sécurité], mais c'est vraiment une portée rarement utilisée dans mon expérience.

0
phreakre