Was ist der Unterschied zwischen "mein" und "unser" in Perl?

188

Ich weiß, was myin Perl ist. Es definiert eine Variable, die nur im Bereich des Blocks existiert, in dem sie definiert ist. Was macht ourdas

Wie unterscheidet oursich von my?

Nathan Fellman
quelle

Antworten:

215

Gute Frage: Wie unterscheidet oursich von myund was macht our?

Zusammenfassend:

Verfügbar seit Perl 5 myist eine Möglichkeit, Nicht-Paket-Variablen zu deklarieren:

  • Privat
  • Neu
  • nicht global
  • getrennt von jedem Paket, so dass auf die Variable nicht in Form von zugegriffen werden kann$package_name::variable .


Andererseits sind ourVariablen Paketvariablen und somit automatisch:

  • globale Variablen
  • definitiv nicht privat
  • nicht unbedingt neu
  • kann außerhalb des Pakets (oder des lexikalischen Bereichs) mit dem qualifizierten Namespace als zugegriffen werden $package_name::variable.


Wenn Sie eine Variable mit ourdeklarieren, können Sie Variablen vorab deklarieren, um sie unter zu verwenden, use strictohne Tippfehler oder Fehler bei der Kompilierung zu erhalten. Seit Perl 5.6 hat es das veraltete ersetzt use vars, das nur einen Dateibereich und keinen lexikalischen Gültigkeitsbereich hatte our.

Zum Beispiel ist der formale, qualifizierte Name für Variable $xinnen package mainist $main::x. Durch das Deklarieren our $xkönnen Sie die nackte $xVariable im Rahmen der Deklaration ohne Strafe (dh ohne daraus resultierenden Fehler) verwenden, wenn das Skript use strictoder verwendet use strict "vars". Der Gültigkeitsbereich kann ein oder zwei oder mehr Pakete oder ein kleiner Block sein.

Fran Corpier
quelle
2
Wie unterscheidet sich unser von lokalen?
Nathan Fellman
17
@ Nathan Fellman, erstellt localkeine Variablen. Es bezieht sich überhaupt nicht auf myund our. localSichert vorübergehend den Wert der Variablen und löscht ihren aktuellen Wert.
Ikegami
1
ourVariablen sind keine Paketvariablen. Sie haben keinen globalen Gültigkeitsbereich, sondern Variablen mit lexikalischem Gültigkeitsbereich, genau wie myVariablen. Sie können das im folgenden Programm sehen : package Foo; our $x = 123; package Bar; say $x;. Wenn Sie eine Paketvariable "deklarieren" möchten, müssen Sie verwenden use vars qw( $x );. our $x;deklariert eine Variable mit lexikalischem Gültigkeitsbereich, die auf die gleichnamige Variable in dem Paket ausgerichtet ist, in dem die ourkompiliert wurde.
Ikegami
60

Die PerlMonks- und PerlDoc-Links von Cartman und Olafur sind eine großartige Referenz - unten ist mein Riss bei einer Zusammenfassung:

myVariablen werden lexikalisch in einem einzelnen Block definiert, der durch {}oder in derselben Datei definiert ist, wenn nicht in {}s. Auf sie kann nicht über Pakete / Unterprogramme zugegriffen werden, die außerhalb desselben lexikalischen Bereichs / Blocks definiert sind.

ourVariablen sind in einem Paket / einer Datei enthalten und können von jedem Code aus aufgerufen werden, der useoder requirediese Paket- / Dateinamenkonflikte zwischen Paketen gelöst werden, indem der entsprechende Namespace vorangestellt wird.

Nur um es abzurunden, localVariablen „dynamisch“ scoped, die sich von myVariablen, dass sie von Subroutinen auch zugänglich sind aus dem gleichen Block genannt.

Bubaker
quelle
+1 für " myVariablen haben einen lexikalischen [...] Gültigkeitsbereich innerhalb derselben Datei, wenn nicht in {}s". Das war nützlich für mich, danke.
Georg
48

Ein Beispiel:

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";
FMc
quelle
11

Der Umgang mit Scoping bietet einen guten Überblick über die Perl-Scoping-Regeln. Es ist alt genug, dass oures im Text nicht behandelt wird. Es wird im Abschnitt Notizen am Ende behandelt.

Der Artikel befasst sich mit Paketvariablen und dem dynamischen Bereich und wie sich dieser von lexikalischen Variablen und dem lexikalischen Bereich unterscheidet.

daotoad
quelle
5

mywird für lokale Variablen verwendet, während oures für globale Variablen verwendet wird.

Weitere Informationen finden Sie unter Variable Scoping in Perl: die Grundlagen .

ismail
quelle
16
Seien Sie vorsichtig, wenn Sie die Wörter lokal und global herumwerfen. Die richtigen Begriffe sind lexikalisch und paketiert. Sie können in Perl keine echten globalen Variablen erstellen, aber einige existieren bereits wie $ _, und local bezieht sich auf Paketvariablen mit lokalisierten Werten (erstellt von local), nicht auf lexikalische Variablen (erstellt mit my).
Chas. Owens
${^Potato}ist global. Es bezieht sich auf dieselbe Variable, unabhängig davon, wo Sie sie verwenden.
MJD
5

Ich bin jemals auf einige Fallstricke bei lexikalischen Erklärungen in Perl gestoßen, die mich durcheinander gebracht haben und die auch mit dieser Frage zusammenhängen. Deshalb füge ich hier einfach meine Zusammenfassung hinzu:

1. Definition oder Erklärung?

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

Die Ausgabe ist var: 42. Wir konnten jedoch nicht sagen, ob local $var = 42;es sich um eine Definition oder Deklaration handelt. Aber wie wäre es damit:

use strict;
use warnings;

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

Das zweite Programm gibt einen Fehler aus:

Global symbol "$var" requires explicit package name.

$varist nicht definiert, was bedeutet, local $var;ist nur eine Erklärung! Stellen Sie vor localdem Deklarieren einer Variablen sicher, dass sie zuvor als globale Variable definiert wurde.

Aber warum scheitert das nicht?

use strict;
use warnings;

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

Die Ausgabe ist : var: 42.

Dies liegt daran $a, dass $bin Perl eine globale Variable vordefiniert ist. Erinnerst du dich an die Sortierfunktion ?

2. Lexikalisch oder global?

Ich war ein C-Programmierer, bevor ich anfing, Perl zu verwenden, daher scheint mir das Konzept der lexikalischen und globalen Variablen einfach zu sein: Es entspricht nur automatischen und externen Variablen in C. Aber es gibt kleine Unterschiede:

In C ist eine externe Variable eine Variable, die außerhalb eines Funktionsblocks definiert ist. Andererseits ist eine automatische Variable eine Variable, die innerhalb eines Funktionsblocks definiert ist. So was:

int global;

int main(void) {
    int local;
}

In Perl sind die Dinge subtil:

sub main {
    $var = 42;
}

&main;

print "var: $var\n";

Die Ausgabe ist var: 42. $varist eine globale Variable, auch wenn sie in einem Funktionsblock definiert ist! Tatsächlich wird in Perl jede Variable standardmäßig als global deklariert.

Die Lektion besteht darin, immer use strict; use warnings;am Anfang eines Perl-Programms hinzuzufügen , wodurch der Programmierer gezwungen wird, die lexikalische Variable explizit zu deklarieren, damit wir nicht durch einige Fehler durcheinander geraten, die für selbstverständlich gehalten werden.

Xu Ding
quelle
Mehr zu ["Erinnern an [$ a und $ b in] sortieren" hier] ( stackoverflow.com/a/26128328/1028230 ). Perl hört nie auf, mich zu verblüffen.
Ruffin
4

Der Perldoc hat eine gute Definition unserer.

Im Gegensatz zu my, das sowohl Speicher für eine Variable zuweist als auch diesem Speicher einen einfachen Namen zur Verwendung im aktuellen Bereich zuordnet, verknüpft unser Benutzer einen einfachen Namen mit einer Paketvariablen im aktuellen Paket zur Verwendung im aktuellen Bereich. Mit anderen Worten, unser hat die gleichen Gültigkeitsregeln wie mein, erstellt jedoch nicht unbedingt eine Variable.

Ólafur Waage
quelle
2

Dies hängt nur ein wenig mit der Frage zusammen, aber ich habe gerade ein (für mich) obskures Stück Perl-Syntax entdeckt, das Sie mit "unseren" (Paket-) Variablen verwenden können, das Sie mit "my" (lokal) nicht verwenden können. Variablen.

#!/usr/bin/perl

our $foo = "BAR";

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

Ausgabe:

BAR
BAZ

Dies funktioniert nicht, wenn Sie "unser" in "mein" ändern.

Mischa Gale
quelle
1
Nicht so. $ foo $ {foo} $ {'foo'} $ {"foo"} funktionieren alle für die Variablenzuweisung oder Dereferenzierung gleich. Vertauschen der unsere in dem obigen Beispiel für meine funktioniert. Was Sie wahrscheinlich erlebt haben, war der Versuch, $ foo als Paketvariable wie $ main :: foo oder $ :: foo zu dereferenzieren, was nur für Paketglobale funktioniert, wie sie mit unserer definiert sind .
Cosmicnet
Nur mit v5.20 erneut getestet, und es gibt definitiv nicht die gleiche Ausgabe mit meinem (es druckt BAR zweimal.)
Misha Gale
1
Mein Test (unter Windows): perl -e "my $foo = 'bar'; print $foo; ${foo} = 'baz'; pr int $foo"Ausgabe: barbaz perl -e "my $foo = 'bar'; print $foo; ${"foo"} = 'baz'; print $foo"Ausgabe: barbaz perl -e "my $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"Ausgabe: barbar Bei meinen Tests war ich also in dieselbe Falle geraten. $ {foo} ist dasselbe wie $ foo, die Klammern sind beim Interpolieren hilfreich. $ {"foo"} ist eigentlich ein Blick nach $ main :: {}, der Hauptsymboltabelle, da diese nur Variablen mit Paketbereich enthält.
Cosmicnet
1
$ {"main :: foo"}, $ {":: foo"} und $ main :: foo sind die gleichen wie $ {"foo"}. Die Abkürzung ist paketsensitiv perl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo", da in diesem Zusammenhang $ {"foo"} jetzt gleich $ {"test :: foo"} ist. Of Symbol Tables and Globs enthält einige Informationen, ebenso wie das Advanced Perl-Programmierbuch. Entschuldigung für meinen vorherigen Fehler.
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";

Wird dies ausgeben:

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 

Wenn bei Verwendung von "use strict" beim Versuch, das Skript auszuführen, der folgende Fehler auftritt:

Global symbol "$test1" requires explicit package name at ./check_global.pl line 24.
Execution of ./check_global.pl aborted due to compilation errors.
Lavi Buchnik
quelle
Bitte geben Sie eine Erklärung. Ein solcher Dumping-Code wird selten als angemessen angesehen.
Scott Solmer
in einfachen Worten: Unsere (wie der Name schon sagt) ist eine Variablendeklaration, um diese Variable an einer beliebigen Stelle im Skript (Funktion, Block usw.) zu verwenden. Jede Variable gehört standardmäßig (falls nicht deklariert) zu "main". Paket, unsere Variable kann auch nach Deklaration eines anderen Pakets im Skript verwendet werden. Die Variable "my" kann nur in diesem Block / dieser Funktion verwendet werden, falls sie in einem Block oder einer Funktion deklariert ist. Falls "meine" Variable in einem Block als nicht geschlossen deklariert wurde, kann sie überall im Scriot, in einem geschlossenen Block oder in einer Funktion als "unsere" Variable verwendet werden, kann aber nicht verwendet werden, wenn das Paket geändert wird
Lavi Buchnik
Mein obiges Skript zeigt, dass wir uns standardmäßig im "main" -Paket befinden. Dann druckt das Skript eine "our" -Variable aus dem "main" -Paket (nicht in einem Block geschlossen) und deklariert dann zwei "my" -Variablen in einer Funktion und Drucken Sie sie aus dieser Funktion. Dann drucken wir eine "unsere" Variable aus einer anderen Funktion, um zu zeigen, dass sie in einer Funktion verwendet werden kann. dann ändern wir das Paket in "geändert" (nicht mehr "main") und drucken die Variable "our" erneut erfolgreich. Der Versuch, eine "my" -Variable außerhalb der Funktion zu drucken, ist fehlgeschlagen. Das Skript zeigt nur den Unterschied zwischen "unserer" und "meiner" Verwendung.
Lavi Buchnik
0

Versuchen Sie einfach, das folgende Programm zu verwenden:

#!/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";
Yugdev
quelle
Dies erklärt den Unterschied zwischen meinem und unserem. Die Variable my verlässt den Gültigkeitsbereich außerhalb der geschweiften Klammern und wird als Müll gesammelt, aber unsere Variable lebt noch.
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;
xoid
quelle
Können Sie erklären, was dieser Code demonstrieren soll? Warum sind ourund myanders? Wie zeigt dieses Beispiel es?
Nathan Fellman
-1

Lassen Sie uns überlegen, was ein Interpreter eigentlich ist: Es ist ein Code, der Werte im Speicher speichert und die Anweisungen in einem Programm, das er interpretiert, auf diese Werte anhand ihrer Namen zugreifen lässt, die in diesen Anweisungen angegeben sind. Die große Aufgabe eines Interpreters besteht also darin, die Regeln zu bestimmen, wie die Namen in diesen Anweisungen verwendet werden sollen, um auf die vom Interpreter gespeicherten Werte zuzugreifen.

Bei der Begegnung mit "my" erstellt der Interpreter eine lexikalische Variable: einen benannten Wert, auf den der Interpreter nur zugreifen kann, während er einen Block ausführt, und nur innerhalb dieses syntaktischen Blocks. Bei der Begegnung mit "our" erstellt der Interpreter einen lexikalischen Alias ​​einer Paketvariablen: Er bindet einen Namen, den der Interpreter fortan als Namen einer lexikalischen Variablen verarbeiten soll, bis der Block fertig ist, an den Wert des Pakets Variable mit dem gleichen Namen.

Der Effekt ist, dass Sie dann so tun können, als würden Sie eine lexikalische Variable verwenden, und die Regeln für die strikte Qualifizierung von Paketvariablen umgehen können. Da der Interpreter bei der ersten Verwendung automatisch Paketvariablen erstellt, kann der Nebeneffekt der Verwendung von "our" auch darin bestehen, dass der Interpreter auch eine Paketvariable erstellt. In diesem Fall werden zwei Dinge erstellt: eine Paketvariable, auf die der Interpreter von überall aus zugreifen kann, vorausgesetzt, sie wird ordnungsgemäß als durch 'use strict' (vorangestellt mit dem Namen des Pakets und zwei Doppelpunkten) bezeichnet, und ihr lexikalischer Alias.

Quellen:

Evgeniy
quelle