Quelle est la différence entre «mon» et «notre» en Perl?


188

Je sais ce qu'il myy a en Perl. Il définit une variable qui n'existe que dans la portée du bloc dans lequel elle est définie. Que fait our-on?

En quoi ourdiffère- myt-il de ?

Réponses:


215

Grande question: en quoi ourdiffère- t -il myet que fait our-il?

En résumé:

Disponible depuis Perl 5, myest un moyen de déclarer des variables non-package, qui sont:

  • privé
  • Nouveau
  • non global
  • séparé de tout package, de sorte que la variable ne soit pas accessible sous la forme de $package_name::variable.


D'autre part, les ourvariables sont des variables de package, et donc automatiquement:

  • variables globales
  • certainement pas privé
  • pas forcément nouveau
  • peut être accessible à l' extérieur du paquet (ou champ lexical) avec l'espace de noms qualifié, comme $package_name::variable.


Déclarer une variable avec ourvous permet de prédéclarer des variables afin de les utiliser sous use strictsans recevoir d'avertissements de frappe ou d'erreurs de compilation. Depuis Perl 5.6, il a remplacé le use varspérimètre obsolète , qui était uniquement défini par fichier, et non lexicalement tel quel our.

Par exemple, le nom formel et qualifié de la variable à l' $xintérieur package mainest $main::x. La déclaration our $xvous permet d'utiliser la $xvariable nue sans pénalité (c'est-à-dire sans erreur résultante), dans le cadre de la déclaration, lorsque le script utilise use strictou use strict "vars". La portée peut être un, deux ou plusieurs packages, ou un petit bloc.


2
Alors, en quoi notre diffère-t-il du local?
Nathan Fellman

17
@Nathan Fellman, localne crée pas de variables. Cela ne concerne pas myet ourdu tout. localsauvegarde temporairement la valeur de la variable et efface sa valeur actuelle.
ikegami

1
ourles variables ne sont pas des variables de package. Ce ne sont pas des variables à portée globale, mais des variables à portée lexique, tout comme des myvariables. Vous pouvez voir que dans le programme suivant: package Foo; our $x = 123; package Bar; say $x;. Si vous souhaitez "déclarer" une variable de package, vous devez utiliser use vars qw( $x );. our $x;déclare une variable de portée lexicale qui a un alias sur la variable du même nom dans le package dans lequel a ourété compilé.
ikegami

60

Les liens PerlMonks et PerlDoc de cartman et Olafur sont une excellente référence - voici ma fissure en un résumé:

myles variables ont une portée lexicale dans un seul bloc défini par {}ou dans le même fichier si ce n'est pas dans {}s. Ils ne sont pas accessibles à partir des packages / sous-programmes définis en dehors du même champ / bloc lexical.

ourles variables sont étendues dans un package / fichier et sont accessibles à partir de tout code qui useou de requirece package / fichier - les conflits de nom sont résolus entre les packages en ajoutant l'espace de noms approprié.

Pour arrondir, les localvariables ont une portée «dynamique», ce qui diffère des myvariables en ce qu'elles sont également accessibles à partir de sous-programmes appelés dans le même bloc.


+1 pour "les myvariables ont une portée lexicale [...] dans le même fichier sinon dans {}s". Cela m'a été utile, merci.
Georg

48

Un exemple:

use strict;

for (1 .. 2){
    # Both variables are lexically scoped to the block.
    our ($o);  # Belongs to 'main' package.
    my  ($m);  # Does not belong to a package.

    # The variables differ with respect to newness.
    $o ++;
    $m ++;
    print __PACKAGE__, " >> o=$o m=$m\n";  # $m is always 1.

    # The package has changed, but we still have direct,
    # unqualified access to both variables, because the
    # lexical scope has not changed.
    package Fubb;
    print __PACKAGE__, " >> o=$o m=$m\n";
}

# The our() and my() variables differ with respect to privacy.
# We can still access the variable declared with our(), provided
# that we fully qualify its name, but the variable declared
# with my() is unavailable.
print __PACKAGE__, " >> main::o=$main::o\n";  # 2
print __PACKAGE__, " >> main::m=$main::m\n";  # Undefined.

# Attempts to access the variables directly won't compile.
# print __PACKAGE__, " >> o=$o\n";
# print __PACKAGE__, " >> m=$m\n";

# Variables declared with use vars() are like those declared
# with our(): belong to a package; not private; and not new.
# However, their scoping is package-based rather than lexical.
for (1 .. 9){
    use vars qw($uv);
    $uv ++;
}

# Even though we are outside the lexical scope where the
# use vars() variable was declared, we have direct access
# because the package has not changed.
print __PACKAGE__, " >> uv=$uv\n";

# And we can access it from another package.
package Bubb;
print __PACKAGE__, " >> main::uv=$main::uv\n";

11

Faire face à la portée est un bon aperçu des règles de portée de Perl. Il est assez ancien pour ourne pas être abordé dans le corps du texte. Il est abordé dans la section Notes à la fin.

L'article parle des variables de package et de la portée dynamique et en quoi cela diffère des variables lexicales et de la portée lexicale.


5

myest utilisé pour les variables locales, alors qu'il ourest utilisé pour les variables globales.

Plus de lecture sur la portée variable en Perl: les bases .


16
Soyez prudent en mélangeant les mots local et mondial. Les termes appropriés sont lexical et package. Vous ne pouvez pas créer de vraies variables globales en Perl, mais certaines existent déjà comme $ _, et local se réfère à des variables de package avec des valeurs localisées (créées par local), pas à des variables lexicales (créées avec my).
Chas. Owens

${^Potato}est mondial. Il fait référence à la même variable quel que soit l'endroit où vous l'utilisez.
MJD

5

J'ai déjà rencontré des pièges sur les déclarations lexicales en Perl qui m'ont dérangé, qui sont également liés à cette question, alors j'ajoute simplement mon résumé ici:

1. Définition ou déclaration?

local $var = 42;
print "var: $var\n";

La sortie est var: 42. Cependant, nous ne pouvons pas dire s'il local $var = 42;s'agit d'une définition ou d'une déclaration. Mais que diriez-vous de ceci:

use strict;
use warnings;

local $var = 42;
print "var: $var\n";

Le deuxième programme lancera une erreur:

Global symbol "$var" requires explicit package name.

$varn'est pas défini, ce qui signifie local $var;est juste une déclaration! Avant d'utiliser localpour déclarer une variable, assurez-vous qu'elle est préalablement définie comme une variable globale.

Mais pourquoi cela n'échouera pas?

use strict;
use warnings;

local $a = 42;
print "var: $a\n";

La sortie est: var: 42.

C'est parce $aque, ainsi que $b, est une variable globale prédéfinie en Perl. Vous vous souvenez de la fonction de tri ?

2. Lexique ou global?

J'étais programmeur C avant de commencer à utiliser Perl, donc le concept de variables lexicales et globales me semble simple: il correspond juste aux variables auto et externes en C.Mais il y a de petites différences:

En C, une variable externe est une variable définie en dehors de tout bloc fonctionnel. D'autre part, une variable automatique est une variable définie à l'intérieur d'un bloc fonction. Comme ça:

int global;

int main(void) {
    int local;
}

En Perl, les choses sont subtiles:

sub main {
    $var = 42;
}

&main;

print "var: $var\n";

La sortie est var: 42. $varest une variable globale même si elle est définie dans un bloc fonction! En fait, en Perl, toute variable est déclarée globale par défaut.

La leçon est de toujours ajouter use strict; use warnings;au début d'un programme Perl, ce qui forcera le programmeur à déclarer la variable lexicale explicitement, afin que nous ne soyons pas dérangés par certaines erreurs prises pour acquises.


Plus d'informations sur ["se souvenir de [$ a et $ b dans] tri" ici] ( stackoverflow.com/a/26128328/1028230 ). Perl ne cesse jamais de m'étonner.
ruffin

4

Le perldoc a une bonne définition de notre.

Contrairement à my, qui alloue à la fois du stockage pour une variable et associe un nom simple à ce stockage pour une utilisation dans la portée actuelle, notre associe un nom simple à une variable de package dans le package actuel, à utiliser dans la portée actuelle. En d'autres termes, notre a les mêmes règles de portée que mon, mais ne crée pas nécessairement une variable.


2

Ceci n'est que quelque peu lié à la question, mais je viens de découvrir un peu (pour moi) obscur de syntaxe Perl que vous pouvez utiliser avec "nos" variables (package) que vous ne pouvez pas utiliser avec "my" (local) variables.

#!/usr/bin/perl

our $foo = "BAR";

print $foo . "\n";
${"foo"} = "BAZ";
print $foo . "\n";

Production:

BAR
BAZ

Cela ne fonctionnera pas si vous remplacez «notre» par «mon».


1
Non. $ foo $ {foo} $ {'foo'} $ {"foo"} fonctionnent tous de la même manière pour l'attribution de variables ou le déréférencement. Échangez le notre dans l'exemple ci-dessus pour mon fonctionne. Ce que vous avez probablement expérimenté a été d'essayer de déréférencer $ foo en tant que variable de package, telle que $ main :: foo ou $ :: foo qui ne fonctionnera que pour les globaux de package, tels que ceux définis avec notre .
Cosmicnet

Juste retesté en utilisant la v5.20, et il ne donne certainement pas la même sortie avec mon (il imprime BAR deux fois.)
Misha Gale

1
Mon test (sur windows): perl -e "my $foo = 'bar'; print $foo; ${foo} = 'baz'; pr int $foo"output: barbaz perl -e "my $foo = 'bar'; print $foo; ${"foo"} = 'baz'; print $foo"output: barbaz perl -e "my $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"output: barbar Donc, lors de mes tests, j'étais tombé dans le même piège. $ {foo} est identique à $ foo, les crochets sont utiles lors de l'interpolation. $ {"foo"} est en fait une recherche vers $ main :: {} qui est la table de symboles principale, en tant que telle ne contient que des variables de portée du package.
Cosmicnet

1
$ {"main :: foo"}, $ {":: foo"} et $ main :: foo sont les mêmes que $ {"foo"}. Le raccourci est sensible aux paquets perl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo", car dans ce contexte $ {"foo"} est maintenant égal à $ {"test :: foo"}. Of Symbol Tables and Globs contient des informations à ce sujet, tout comme le livre de programmation Advanced Perl. Désolé pour mon erreur précédente.
Cosmicnet

0
print "package is: " . __PACKAGE__ . "\n";
our $test = 1;
print "trying to print global var from main package: $test\n";

package Changed;

{
        my $test = 10;
        my $test1 = 11;
        print "trying to print local vars from a closed block: $test, $test1\n";
}

&Check_global;

sub Check_global {
        print "trying to print global var from a function: $test\n";
}
print "package is: " . __PACKAGE__ . "\n";
print "trying to print global var outside the func and from \"Changed\" package:     $test\n";
print "trying to print local var outside the block $test1\n";

Sortira ceci:

package is: main
trying to print global var from main package: 1
trying to print local vars from a closed block: 10, 11
trying to print global var from a function: 1
package is: Changed
trying to print global var outside the func and from "Changed" package: 1
trying to print local var outside the block 

Dans le cas où l'utilisation de "use strict" obtiendra cet échec lors de la tentative d'exécution du script:

Global symbol "$test1" requires explicit package name at ./check_global.pl line 24.
Execution of ./check_global.pl aborted due to compilation errors.

Veuillez fournir une sorte d'explication. Un code de vidage comme celui-ci est rarement considéré comme approprié.
Scott Solmer

en termes simples: Notre (comme son nom l'indique) est une déclinaison de variable pour utiliser cette variable depuis n'importe quel endroit du script (fonction, bloc etc ...), chaque variable par défaut (au cas où elle n'est pas déclarée) appartient à "main" package, notre variable peut toujours être utilisée même après la décomposition d'un autre package dans le script. "ma" variable dans le cas déclaré dans un bloc ou une fonction, ne peut être utilisée que dans ce bloc / cette fonction. dans le cas où "ma" variable a été déclarée non fermée dans un bloc, elle peut être utilisée n'importe où dans le scriot, dans un bloc fermé aussi bien ou dans une fonction que "notre" variable, mais ne peut pas être utilisée en cas de changement de package
Lavi Buchnik

Mon script ci-dessus montre que par défaut nous sommes dans le package "main", puis le script imprime une "notre" variable du package "main" (non fermée dans un bloc), puis nous déclarons deux variables "my" dans une fonction et imprimez-les à partir de cette fonction. puis nous imprimons une variable "notre" à partir d'une autre fonction pour montrer qu'elle peut être utilisée dans une fonction. puis nous changeons le paquet en "changé" (pas "main" plus), et nous imprimons à nouveau la variable "notre" avec succès. puis en essayant d'imprimer une variable "mon" en dehors de la fonction et a échoué. le script montrant simplement la différence entre "notre" et "mon" usage.
Lavi Buchnik

0

Essayez simplement d'utiliser le programme suivant:

#!/usr/local/bin/perl
use feature ':5.10';
#use warnings;
package a;
{
my $b = 100;
our $a = 10;


print "$a \n";
print "$b \n";
}

package b;

#my $b = 200;
#our $a = 20 ;

print "in package b value of  my b $a::b \n";
print "in package b value of our a  $a::a \n";

Cela explique la différence entre mon et notre. La variable my sort du champ d'application en dehors des accolades et est récupérée de la mémoire, mais la variable our vit toujours.
Yugdev

-1
#!/usr/bin/perl -l

use strict;

# if string below commented out, prints 'lol' , if the string enabled, prints 'eeeeeeeee'
#my $lol = 'eeeeeeeeeee' ;
# no errors or warnings at any case, despite of 'strict'

our $lol = eval {$lol} || 'lol' ;

print $lol;

Pouvez-vous expliquer ce que ce code est censé démontrer? Pourquoi ouret mydifférent? Comment cet exemple le montre-t-il?
Nathan Fellman

-1

Pensons à ce qu'est réellement un interpréteur: c'est un morceau de code qui stocke des valeurs en mémoire et laisse les instructions d'un programme qu'il interprète accéder à ces valeurs par leurs noms, qui sont spécifiés dans ces instructions. Ainsi, le gros travail d'un interprète est de façonner les règles sur la façon dont nous devrions utiliser les noms dans ces instructions pour accéder aux valeurs stockées par l'interpréteur.

En rencontrant "mon", l'interpréteur crée une variable lexicale: une valeur nommée à laquelle l'interpréteur ne peut accéder que pendant qu'il exécute un bloc, et uniquement à partir de ce bloc syntaxique. En rencontrant "notre", l'interpréteur crée un alias lexical d'une variable de package: il lie un nom, que l'interpréteur est supposé désormais traiter comme le nom d'une variable lexicale, jusqu'à ce que le bloc soit terminé, à la valeur du package variable avec le même nom.

L'effet est que vous pouvez alors prétendre que vous utilisez une variable lexicale et contourner les règles de «use strict» sur la qualification complète des variables de package. Puisque l'interpréteur crée automatiquement des variables de package lors de leur première utilisation, l'effet secondaire de l'utilisation de "notre" peut également être que l'interpréteur crée également une variable de package. Dans ce cas, deux choses sont créées: une variable de package, à laquelle l'interpréteur peut accéder de partout, à condition qu'elle soit correctement désignée comme demandé par 'use strict' (précédée du nom de son package et de deux deux-points), et son alias lexical.

Sources:

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.