Wiem, co my
jest w Perlu. Definiuje zmienną, która istnieje tylko w zakresie bloku, w którym jest zdefiniowana. Co ma our
zrobić?
Czym się our
różni my
?
Wiem, co my
jest w Perlu. Definiuje zmienną, która istnieje tylko w zakresie bloku, w którym jest zdefiniowana. Co ma our
zrobić?
Czym się our
różni my
?
Odpowiedzi:
Świetne pytanie: czym się our
różni my
i co robi our
?
W podsumowaniu:
Dostępny od Perla 5 my
jest sposobem deklarowania zmiennych nie-pakietowych, którymi są:
$package_name::variable
.Z drugiej strony our
zmienne są zmiennymi pakietowymi, a zatem automatycznie:
$package_name::variable
.Zadeklarowanie zmiennej za pomocą our
pozwala wstępnie określić zmienne w celu ich użycia use strict
bez 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 $x
wewnątrz package main
to $main::x
. Zadeklarowanie our $x
pozwala na użycie $x
zmiennej gołej bez kary (tj. Bez błędu wynikowego), w zakresie deklaracji, gdy skrypt używa use strict
lub use strict "vars"
. Zakres może obejmować jeden, dwa lub więcej pakietów lub jeden mały blok.
local
nie tworzy zmiennych. To nie odnosi się do my
i our
w ogóle. local
tymczasowo tworzy kopię zapasową wartości zmiennej i kasuje jej bieżącą wartość.
our
zmienne nie są zmiennymi pakietowymi. Nie mają one zasięgu globalnego, ale zmienne o zasięgu leksykalnym, podobnie jak my
zmienne. 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 our
została skompilowana.
Linki PerlMonks i PerlDoc od Cartmana i Olafura są świetnym odniesieniem - poniżej moje podsumowanie:
my
zmienne 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.
our
Zmienne mają zasięg w pakiecie / pliku i są dostępne z dowolnego kodu tego use
lub require
tego pakietu / pliku - konflikty nazw są rozwiązywane między pakietami przez dodanie odpowiedniej przestrzeni nazw.
Aby to podsumować, local
zmienne mają zakres „dynamiczny”, różniący się od my
zmiennych tym, że są również dostępne z podprogramów wywoływanych w tym samym bloku.
my
zmiennych ma zasięg [...] leksykalny w tym samym pliku, jeśli nie jest w {}
s”. To mi się przydało, dzięki.
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";
Radzenie sobie z Scopingiem jest dobrym przeglądem zasad scopingu Perla. Jest wystarczająco stary, że our
nie 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.
my
służy do zmiennych lokalnych, natomiast our
do zmiennych globalnych.
Więcej lektur w Variable Scoping w Perlu: podstawy .
${^Potato}
jest globalny. Odnosi się do tej samej zmiennej, niezależnie od tego, gdzie jej używasz.
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.
$var
nie jest zdefiniowany, co oznacza local $var;
tylko deklarację! Przed użyciem local
do 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 $b
jest 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
. $var
jest 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.
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ą.
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”.
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: barbar
Wię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.
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.
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.
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";
#!/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;
our
i czym się my
różnią? Jak pokazuje ten przykład?
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: