Jaka jest różnica między „moim” a „naszym” w Perlu?

188

Wiem, co myjest w Perlu. Definiuje zmienną, która istnieje tylko w zakresie bloku, w którym jest zdefiniowana. Co ma ourzrobić?

Czym się ourróżni my?

Nathan Fellman
źródło

Odpowiedzi:

215

Świetne pytanie: czym się ourróżni myi co robi our?

W podsumowaniu:

Dostępny od Perla 5 myjest sposobem deklarowania zmiennych nie-pakietowych, którymi są:

  • prywatny
  • Nowy
  • nieglobalny
  • oddzielić od żadnego pakietu, aby nie można było uzyskać dostępu do zmiennej w postaci $package_name::variable.


Z drugiej strony ourzmienne są zmiennymi pakietowymi, a zatem automatycznie:

  • zmienne globalne
  • zdecydowanie nie prywatny
  • niekoniecznie nowy
  • można uzyskać dostęp poza pakietem (lub zakresem leksykalnym) za pomocą kwalifikowanej przestrzeni nazw, as $package_name::variable.


Zadeklarowanie zmiennej za pomocą ourpozwala wstępnie określić zmienne w celu ich użycia use strictbez uzyskiwania ostrzeżeń literowych lub błędów podczas kompilacji. Od Perla 5.6 zastąpił on przestarzały use vars, który miał jedynie zakres plików, a nie leksykalny jak jest our.

Na przykład formalna, kwalifikowana nazwa zmiennej $xwewnątrz package mainto $main::x. Zadeklarowanie our $xpozwala na użycie $xzmiennej gołej bez kary (tj. Bez błędu wynikowego), w zakresie deklaracji, gdy skrypt używa use strictlub use strict "vars". Zakres może obejmować jeden, dwa lub więcej pakietów lub jeden mały blok.

Fran Corpier
źródło
2
Czym zatem różni się nasz lokalny?
Nathan Fellman
17
@Nathan Fellman, localnie tworzy zmiennych. To nie odnosi się do myi ourw ogóle. localtymczasowo tworzy kopię zapasową wartości zmiennej i kasuje jej bieżącą wartość.
ikegami,
1
ourzmienne nie są zmiennymi pakietowymi. Nie mają one zasięgu globalnego, ale zmienne o zasięgu leksykalnym, podobnie jak myzmienne. Widać, że w następującym programie: package Foo; our $x = 123; package Bar; say $x;. Jeśli chcesz „zadeklarować” zmienną pakietu, musisz użyć use vars qw( $x );. our $x;deklaruje zmienną o zasięgu leksykalnym, która jest aliasowana do zmiennej o tej samej nazwie w pakiecie, w którym ourzostała skompilowana.
ikegami,
60

Linki PerlMonks i PerlDoc od Cartmana i Olafura są świetnym odniesieniem - poniżej moje podsumowanie:

myzmienne mają zasięg leksykalny w obrębie jednego bloku zdefiniowanego przez {}ten sam plik lub w obrębie tego samego pliku, jeśli nie {}jest to s. Nie są dostępne z pakietów / podprogramów zdefiniowanych poza tym samym zakresem / blokiem leksykalnym.

ourZmienne mają zasięg w pakiecie / pliku i są dostępne z dowolnego kodu tego uselub requiretego pakietu / pliku - konflikty nazw są rozwiązywane między pakietami przez dodanie odpowiedniej przestrzeni nazw.

Aby to podsumować, localzmienne mają zakres „dynamiczny”, różniący się od myzmiennych tym, że są również dostępne z podprogramów wywoływanych w tym samym bloku.

bubaker
źródło
+1 dla „ myzmiennych ma zasięg [...] leksykalny w tym samym pliku, jeśli nie jest w {}s”. To mi się przydało, dzięki.
Georg
48

Przykład:

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
źródło
11

Radzenie sobie z Scopingiem jest dobrym przeglądem zasad scopingu Perla. Jest wystarczająco stary, że ournie jest omawiany w tekście. Jest to omówione w części Notatki na końcu.

W artykule omówiono zmienne pakietu i zakres dynamiczny oraz różnice między nimi a zmiennymi leksykalnymi i zakresem leksykalnym.

daotoad
źródło
5

mysłuży do zmiennych lokalnych, natomiast ourdo zmiennych globalnych.

Więcej lektur w Variable Scoping w Perlu: podstawy .

ismail
źródło
16
Zachowaj ostrożność, przewracając słowa lokalne i globalne. Właściwe warunki są leksykalne i pakietowe. Nie możesz tworzyć prawdziwych zmiennych globalnych w Perlu, ale niektóre już istnieją, takie jak $ _, a local odnosi się do zmiennych pakietu ze zlokalizowanymi wartościami (utworzonymi przez local), a nie do zmiennych leksykalnych (utworzonych za pomocą my).
Chas. Owens
${^Potato}jest globalny. Odnosi się do tej samej zmiennej, niezależnie od tego, gdzie jej używasz.
MJD,
5

Zetknąłem się kiedyś z pewnymi pułapkami związanymi z deklaracjami leksykalnymi w Perlu, które mnie zawiodły, które są również związane z tym pytaniem, więc dodam tutaj moje streszczenie:

1. Definicja lub deklaracja?

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

Dane wyjściowe to var: 42. Nie mogliśmy jednak stwierdzić, czy local $var = 42;jest to definicja czy deklaracja. Ale co z tym:

use strict;
use warnings;

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

Drugi program zgłosi błąd:

Global symbol "$var" requires explicit package name.

$varnie jest zdefiniowany, co oznacza local $var;tylko deklarację! Przed użyciem localdo zadeklarowania zmiennej upewnij się, że jest ona wcześniej zdefiniowana jako zmienna globalna.

Ale dlaczego to nie zawiedzie?

use strict;
use warnings;

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

Wyjście jest: var: 42.

To dlatego $a, że oprócz tego $bjest globalną zmienną predefiniowaną w Perlu. Pamiętasz funkcję sortowania ?

2. Leksykalny czy globalny?

Byłem programistą C, zanim zacząłem używać Perla, więc koncepcja zmiennych leksykalnych i globalnych wydaje mi się prosta: po prostu odpowiada zmiennym auto i zewnętrznym w C. Ale są małe różnice:

W C zmienna zewnętrzna jest zmienną zdefiniowaną poza dowolnym blokiem funkcyjnym. Z drugiej strony zmienna automatyczna to zmienna zdefiniowana w bloku funkcyjnym. Lubię to:

int global;

int main(void) {
    int local;
}

W Perlu rzeczy są subtelne:

sub main {
    $var = 42;
}

&main;

print "var: $var\n";

Dane wyjściowe to var: 42. $varjest zmienną globalną, nawet jeśli jest zdefiniowana w bloku funkcyjnym! W rzeczywistości w Perlu każda zmienna jest domyślnie deklarowana jako globalna.

Lekcja polega na tym, aby zawsze dodawać use strict; use warnings;na początku programu Perl, co zmusi programistę do jawnego zadeklarowania zmiennej leksykalnej, abyśmy nie pomylili się z błędami przyjętymi za pewnik.

Xu Ding
źródło
Więcej informacji na temat [„zapamiętywania [$ a i $ b in] sort” tutaj] ( stackoverflow.com/a/26128328/1028230 ). Perl nigdy mnie nie zaskakuje.
ruffin
4

Perldoc ma dobrą definicję naszego.

W przeciwieństwie do mojego, który zarówno przydziela pamięć dla zmiennej, jak i kojarzy prostą nazwę z tą pamięcią do użytku w bieżącym zakresie, nasi użytkownicy łączą prostą nazwę ze zmienną pakietu w bieżącym pakiecie, do użytku w bieżącym zakresie. Innymi słowy, nasze mają takie same zasady określania zakresu jak moje, ale niekoniecznie tworzą zmienną.

Lalafur Waage
źródło
2

Jest to tylko w pewnym stopniu związane z pytaniem, ale właśnie odkryłem (dla mnie) nieco niejasną składnię perla, której można używać ze zmiennymi „our” (pakiet), których nie można używać z „my” (lokalnie) zmienne.

#!/usr/bin/perl

our $foo = "BAR";

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

Wynik:

BAR
BAZ

To nie zadziała, jeśli zmienisz „nasze” na „moje”.

Misha Gale
źródło
1
Skąd. $ foo $ {foo} $ {'foo'} $ {"foo"} działają tak samo dla przypisywania zmiennych lub dereferencji. Zamiana naszego w powyższym przykładzie na mój działa. To, czego prawdopodobnie doświadczyłeś, to próba wyrejestrowania $ foo jako zmiennej pakietu, takiej jak $ main :: foo lub $ :: foo, która będzie działać tylko dla globałów pakietów, takich jak te zdefiniowane w naszym .
Cosmicnet
Właśnie przetestowałem przy użyciu v5.20 i zdecydowanie nie daje tego samego wyniku z moim (drukuje BAR dwukrotnie.)
Misha Gale
1
Mój test ( w systemie Windows): perl -e "my $foo = 'bar'; print $foo; ${foo} = 'baz'; pr int $foo"wyjście: barbaz perl -e "my $foo = 'bar'; print $foo; ${"foo"} = 'baz'; print $foo"wyjście: barbaz perl -e "my $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"wyjście: barbarWięc w moich testach wpadłem w tę samą pułapkę. $ {foo} jest tym samym co $ foo, nawiasy są przydatne podczas interpolacji. $ {„foo”} to tak naprawdę spojrzenie do $ main :: {}, która jest główną tabelą symboli, ponieważ zawiera tylko zmienne o zasięgu pakietowym.
Cosmicnet
1
$ {"main :: foo"}, $ {":: foo"} i $ main :: foo są takie same jak $ {"foo"}. Stenografia jest wrażliwa na pakiety perl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo", ponieważ w tym kontekście $ {„foo”} jest teraz równe $ {„test :: foo”}. Tabele symboli i globusy zawiera pewne informacje, podobnie jak książka programowania Advanced Perl. Przepraszam za mój poprzedni błąd.
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";

Wyprowadzi to:

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 

W przypadku, gdy użycie „użyj ścisłego” spowoduje błąd podczas próby uruchomienia skryptu:

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
źródło
Proszę podać jakieś wyjaśnienie. Taki kod zrzutu rzadko jest uważany za odpowiedni.
Scott Solmer,
w prostych słowach: Nasza (jako nazwa sais) jest deklaracją zmiennej, aby używać tej zmiennej z dowolnego miejsca w skrypcie (funkcja, blok itp.), domyślnie każda zmienna (jeśli nie została zadeklarowana) należy do „głównej” pakiet, nasza zmienna nadal może być używana nawet po deklaracji innego pakietu w skrypcie. Zmienna „my” w przypadku zadeklarowana w bloku lub funkcji może być używana tylko w tym bloku / funkcji. w przypadku, gdy zmienna „moja” została zadeklarowana jako niezamknięta w bloku, można jej użyć w dowolnym miejscu w skrypcie, również w zamkniętym bloku lub w funkcji jako zmienna „nasza”, ale nie można jej użyć w przypadku zmiany pakietu
Lavi Buchnik,
Mój skrypt powyżej pokazuje, że domyślnie znajdujemy się w pakiecie „głównym”, następnie skrypt wypisuje „naszą” zmienną z pakietu „głównego” (niezamkniętego w bloku), a następnie deklarujemy dwie zmienne „moje” w funkcji i wydrukuj je z tej funkcji. następnie wypisujemy „naszą” zmienną z innej funkcji, aby pokazać, że można jej użyć w funkcji. następnie zmieniamy pakiet na „zmieniono” (już nie „główny”) i ponownie pomyślnie wypisujemy zmienną „nasza”. następnie próba wydrukowania zmiennej „my” poza funkcją i nie powiodła się. skrypt pokazuje tylko różnicę między użytkowaniem „nasze” i „moje”.
Lavi Buchnik,
0

Spróbuj użyć następującego programu:

#!/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";
Jugdev
źródło
To wyjaśnia różnicę między moim a naszym. Moja zmienna wykracza poza zakres nawiasów klamrowych i jest usuwana, ale nasza zmienna nadal żyje.
Jugdev,
-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
źródło
Czy możesz wyjaśnić, co ten kod ma zademonstrować? Dlaczego ouri czym się myróżnią? Jak pokazuje ten przykład?
Nathan Fellman
-1

Zastanówmy się, czym tak naprawdę jest interpreter: jest to fragment kodu, który przechowuje wartości w pamięci i pozwala instrukcjom w interpretowanym programie na dostęp do tych wartości po ich nazwach, które są określone w tych instrukcjach. Tak więc wielkim zadaniem tłumacza jest kształtowanie zasad, w jaki sposób powinniśmy używać nazw w tych instrukcjach, aby uzyskać dostęp do wartości przechowywanych przez tłumacza.

Po napotkaniu „moje” interpreter tworzy zmienną leksykalną: nazwaną wartość, do której interpreter może uzyskać dostęp tylko podczas wykonywania bloku i tylko z tego bloku składniowego. Po napotkaniu „nasz” interpreter tworzy aleksualny alias zmiennej pakietowej: wiąże nazwę, którą interpreter powinien odtąd przetwarzać jako nazwę zmiennej leksykalnej, aż do zakończenia bloku, do wartości pakietu zmienna o tej samej nazwie.

W efekcie możesz udawać, że używasz zmiennej leksykalnej i omijasz zasady „używaj surowo” przy pełnej kwalifikacji zmiennych pakietowych. Ponieważ interpreter automatycznie tworzy zmienne pakietu przy ich pierwszym użyciu, efektem ubocznym użycia „nasz” może być również to, że interpreter tworzy również zmienną pakietu. W tym przypadku tworzone są dwie rzeczy: zmienna pakietu, do której interpreter może uzyskać dostęp z dowolnego miejsca, pod warunkiem, że jest odpowiednio oznaczona zgodnie z żądaniem wyrażenia „ścisłe użycie” (z nazwą pakietu i dwóch dwukropków) oraz alias leksykalny.

Źródła:

Evgeniy
źródło