J'ai quelques doutes quant à la portée de local/our
en Perl. J'ai lu beaucoup de documentation mais la confusion est toujours là. Voici les confusions
Quelle est la portée de local
?
ce que je lis est -> local copie la valeur de variable globale, change la valeur, l'utilisateur l'utilisera et en dehors du bloc, il conservera la valeur globale
Confusion -> my
fait la même chose. Le seul avantage que je vois est que certaines variables telles que $package::var
ne peuvent pas être déclarées avec mon étendue, mais peuvent l'être avec une étendue locale. Quoi d'autre pour les locaux
Quelle est la variable "globale"?
Ce qui est lu est -> Sa portée est dans le paquet. Fondamentalement, nous plaçons la variable globale dans le tableau @EXPORT
et l’utilisons ou lui ajoutons l’espace de nom à utiliser dans d’autres packages.
doute -> Encore une fois, si nous déclarons une variable avec my
scope dans main uniquement, nous pourrons alors accéder à la variable dans tout le package. Est-ce correct? Est-il possible d'ajouter les variables my
scoped dans le tableau @EXPORT
et de les utiliser dans d'autres packages?
Je pense que les variables globales sont déclarées avec le mot clé our
. Y a-t-il un autre moyen de le faire?
Cette question peut sembler répétitive mais je suis confus
En termes de portée, il existe deux types de variables dans Perl.
Voici différentes façons de créer une variable.
my
crée une variable lexicale.our
crée une variable lexicale aliasée avec la variable du même nom dans le package actuel. En d'autres termes, our $foo;
est identique à alias my $foo = $The::Current::Package::foo;
.local
ne crée aucune variable. Il sauvegarde simplement une variable jusqu'à la destruction de la portée lexicale actuelle.
my
fait la même chose.
local
ne modifie pas la portée d'une variable. Bien qu'une variable lexicale ne soit visible que dans une étendue lexicale, une variable globale localisée est toujours visible sur l'ensemble de l'interpréteur.
$x = 123;
sub foo { print "$x\n"; }
{ local $x = 456; foo(); } # 456
foo(); # 123
$x = 123;
sub foo { print "$x\n"; }
{ my $x = 456; foo(); } # 123
foo(); # 123
Quoi d'autre pour
local
local
est principalement utilisé pour approximer la fonctionnalité de my
pour les variables qui ne pourraient autrement pas être déclarées lexicalement.
(Historiquement, c'était toutes les variables. Depuis la version 5.6, seules les variables de ponctuation ne peuvent pas être déclarées lexicalement.)
Quelle est la variable "globale"?
Variable pouvant être vue de manière globale, c’est-à-dire par n’importe quel code de l’interpréteur.
Est-il possible d'ajouter les variables my scoped dans le tableau @EXPORT et de les utiliser dans d'autres packages?
@EXPORT
est utilisé par l'exportateur. L'exportateur ne pourrait trouver que des symboles globaux (les fichiers étant compilés dans de nouvelles portées lexicales), donc @EXPORT
ne doit contenir que des symboles globaux.
Il existe deux types de variables, à portée lexicale et à portée mondiale.
Dans Perl, avant la version 5, il n'y en avait qu'une portée globale. Ces variables sont les variables de package. Ces variables sont disponibles partout dans le programme si vous utilisez le préfixe du package.
Le mot clé local
a été introduit pour permettre de modifier la valeur de l'une de ces variables globales de package dans une portée limitée, telle que celle d'un sous-programme. Il enregistre l'ancienne valeur sur une pile lors de la saisie de l'étendue avec l'instruction local
et lors de la sortie, il restaure l'ancienne valeur. Ce sont toujours des paquets globaux, ce qui signifie qu'ils sont toujours disponibles partout. Si vous vous trouvez dans une portée avec une variable local
et que vous appelez un sous-programme, cette variable est toujours visible dans ce sous-programme.
Le mot clé my
a été introduit dans la version 5 et fournit des variables à portée lexicale. Ces variables n'existent que dans la portée où elles sont déclarées. Cela signifie que si vous appelez un sous-programme, cette variable my
n'est pas visible. En quittant une étendue, les variables my
disparaissent tout simplement. Vous devriez préférer utiliser les variables my
lorsque cela est possible, car vous ne voulez pas que vos variables soient visibles dans les sous-routines que vous appelez. Vous ne pouvez pas utiliser ces types de variables dans la liste @EXPORT
car ces variables ne sont pas visibles en dehors de leur portée.
Enfin, le mot clé our
est une combinaison des deux, en ce sens qu'il vous donne une variable qui est un package global, mais que cette variable est étendue lexicalement. Cela signifie qu’elle sera disponible n’importe où dans le programme, mais qu’à la fin du bloc englobant, vous ne pourrez plus vous référer à cette variable.
sub mess_with_foo {
$foo=0;
}
sub myfunc {
my $foo=20;
mess_with_foo();
print $foo;
}
myfunc();
sub mess_with_foo {
$foo=0;
}
sub myfunc {
local $foo=20;
mess_with_foo();
print $foo;
}
myfunc();
Exemple 1 imprime 20
car mess_with_foo()
n'a pas pu voir my $foo
. Cela ne pourrait pas le changer. my $foo
n'apparaît que dans le cadre de myfunc()
.
Exemple 2 imprime 0
car mess_with_foo()
peut voir my $foo
et le changer. local $foo
peut être vu dans sa portée de myfunc()
ET dans la portée de toute fonction appelée à partir de sa portée de myfunc()
.
C'est la seule différence. Ni my $foo
ni local $foo
ne seront visibles en dehors de leur portée de myfunc()
.
Voici ce que j'ai découvert à propos des portées variables: Mes décalcomanies sont assez claires et simples si elles sont utilisées à l'intérieur de blocs. S'ils sont utilisés en dehors de tout bloc, ils sont un peu différents, ce qui signifie qu'une variable my déclarée en dehors d'un bloc est visible même à l'intérieur de fonctions appelées n'importe où dans le même fichier, à condition que ces fonctions soient définies dans le même fichier. Cependant, si elles sont déclarées à l'intérieur d'un bloc, elles ne sont pas visibles par les fonctions, même si elles sont appelées à partir du même bloc. Toutes mes variables semblent vivre sur la pile. Et: vous ne pouvez pas les localiser avec local.
nos variables vivent sur le tas. Même si vous avez une variable my du même nom, vous pouvez toujours accéder à notre variable via $ {'var'}, qui recherche une variable de ce nom dans la table des symboles et la déréférence. Par contre, mes variables n'ont pas d'entrées dans la table des symboles.
les variables locales me paraissent être des reliques d'anciennes versions de Perl. Ce ne sont que des réaffectations à des variables globales (nos) avec une portée de bloc et reprennent leurs valeurs précédentes après la fin du bloc. Je ne vois aucun sens réel à les utiliser.
Mon petit programme ci-dessous montre tout cela, et il montre à quel point un test déclaré () est manquant, au-delà du test bien connu, defini, pour identifier les variables non déclarées en tant que telles.
1 #!/usr/bin/Perl
2
3 use strict;
4
5 ### This is about variable scoping with my, our and local
6 my $fsv = "file scope"; # visible for all code in this file
7 our $gsv = "global scope"; # not different from my $fsv, except in packages
8 our $lsv = "global"; # global scope, but localized in subsequent block
9
10 {
11 my $bsv = "Lex scope"; # visible only inside this block, not even in subs called from here
12 $gsv = "visible everywhere";
13 local $lsv = "global, but localized val";
14
15 print "This is variable \$bsv with value $bsv inside block\n";
16 print "This is variable \$fsv with value $fsv inside block\n";
17 print "This is variable \$lsv with value $lsv inside block\n\n";
18 print_vars("calledfromblock");
19 }
20
21 print_vars("calledfromoutside");
22
23
24 no strict 'vars'; # needed if testing variable for declaredness rather than definedness
25 if ( defined $bsv ) {
26 print "\$bsv as defined outside braces: $bsv\n"
27 } else {
28 print "\$bsv not defined outside braces\n";
29 }
30 print "This is variable \$lsv with value $lsv outside block\n";
31 # use strict 'vars'; # no strict 'vars' effective even in sub print_vars unless switched back on
32
33 sub print_vars
34 {
35 my $whence = shift;
36 my $gsv = "my variable";
37 no strict 'refs'; # needed to access the global var $gsv using ${'gsv'} despite the my decaration
38
39 if ( $whence eq "calledfromblock" ) {
40 print "\t print_vars called from within the block:\n";
41 ( defined $bsv ) ? print "\$bsv is $bsv inside sub\n" : print "\$bsv not defined inside sub\n";
42 ( defined $fsv ) ? print "\$fsv is $fsv inside sub\n" : print "\$fsv not defined inside sub\n";
43 ( defined ${'gsv'} ) ? print "\$gsv is ${'gsv'} inside sub\n" : print "\$gsv not defined inside sub\n";
44 ( defined ${'lsv'} ) ? print "\$lsv is ${'lsv'} inside sub\n" : print "\$lsv not defined inside sub\n";
45 } else {
46 print "\t print_vars called from outside the block:\n";
47 ( defined $bsv ) ? print "\$bsv is $bsv inside sub\n" : print "\$bsv not defined inside sub\n";
48 ( defined $fsv ) ? print "\$fsv is $fsv inside sub\n" : print "\$fsv not defined inside sub\n";
49 ( defined $gsv ) ? print "\$gsv is $gsv inside sub\n" : print "\$gsv not defined inside sub\n";
50 ( defined $lsv ) ? print "\$lsv is $lsv inside sub\n" : print "\$lsv not defined inside sub\n";
51 }
52 print "\n";
53 }