Perl'de 'my' ve 'our' arasındaki fark nedir?


188

myPerl'de ne olduğunu biliyorum . Yalnızca tanımlandığı bloğun kapsamında bulunan bir değişkeni tanımlar. Ne yapar our?

Nasıl mu ourfarklı my?

Yanıtlar:


215

Harika soru: ourFarkı mynedir ve ne yapar our?

Özetle:

Perl 5'ten beri mevcut olan, mypaket dışı değişkenleri bildirmenin bir yoludur, bunlar:

  • özel
  • yeni
  • küresel olmayan
  • Değişken böylece, herhangi bir paket ayrı değil şeklinde erişilebilir $package_name::variable.


Öte yandan, ourdeğişkenler paket değişkenleridir ve dolayısıyla otomatik olarak:

  • küresel değişkenler
  • kesinlikle özel değil
  • ille de yeni değil
  • olabilir olarak, kaliteli ad ile paket (ya da sözcük kapsamı) dışında erişilebilir $package_name::variable.


Bir değişkeni ourtanımlamak, değişkenleri use strictyazım hatası veya derleme zamanı hataları almadan kullanmak için önceden bildirmenizi sağlar . Perl 5.6'dan beri use vars, sadece dosya kapsamındaki ve sözlüksel olarak kapsam dışı olan eski olanın yerini almıştır our.

Örneğin, değişken için resmi nitelikli adı $xiçeriden package mainolduğunu $main::x. Bildirme , komut dosyasını veya our $xkullandığında, açık $xdeğişkenini ceza olmadan (yani, sonuçta ortaya çıkan bir hata olmadan) kullanmanıza izin verir . Kapsam bir veya iki veya daha fazla paket veya bir küçük blok olabilir.use strictuse strict "vars"


2
Peki bizim yerelden farkı nedir?
Nathan Fellman

17
@Nathan Fellman, localdeğişken oluşturmaz. Hiçbir şekilde myve hiç alakalı değildir our. localdeğişkenin değerini geçici olarak yedekler ve geçerli değerini siler.
ikegami

1
ourdeğişkenler paket değişkenleri değildir. Küresel kapsamda değil, aynı değişkenler gibi sözlüksel olarak kapsamlı mydeğişkenler. Aşağıdaki programda görebilirsiniz: package Foo; our $x = 123; package Bar; say $x;. Bir paket değişkenini "bildirmek" istiyorsanız, kullanmanız gerekir use vars qw( $x );. , derlendiği our $x;paketteki aynı adlı değişkenle diğer adla adlandırılan sözlüksel olarak kapsamlı bir değişkeni bildirir our.
ikegami

60

Cartman ve Olafur'dan PerlMonks ve PerlDoc bağlantıları harika bir referanstır - aşağıda bir özette benim çatlak:

mydeğişkenler, s {}içinde değilse, aynı dosya tarafından veya aynı dosya içinde tanımlanan tek bir blok içinde sözcüksel olarak kapsamlandırılır {}. Aynı sözcüksel kapsamın / bloğun dışında tanımlanan paketlerden / altyordamlardan erişilemez.

ourdeğişkenler bir paket / dosya içinde kapsamlı ve herhangi bir kod erişilebilir olan useveya requirebu paket / dosya - adı çakışmaları uygun ad alanını ekleyerek bu paketler arasında çözülür.

Yuvarlamak için, localdeğişkenler "dinamik olarak" kapsamlıdır, mydeğişkenlerden farklıdır, çünkü aynı blok içinde çağrılan alt rutinlerden de erişilebilirler.


+1 için " mydeğişkenler aynı dosya içinde {}s olarak yer almıyorsa [...] " Bu benim için yararlı oldu, teşekkürler.
Georg

48

Bir örnek:

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

Kapsam Belirleme ile başa çıkmak Perl kapsam belirleme kurallarına iyi bir genel bakıştır. ourMetnin gövdesinde tartışılmayacak kadar eski . Sondaki Notlar bölümünde ele alınmaktadır .

Makale, paket değişkenleri ve dinamik kapsamdan ve bunun sözcük değişkenlerinden ve sözcüksel kapsamdan nasıl farklı olduğu hakkında konuşuyor.


5

myyerel değişkenler ouriçin kullanılırken, global değişkenler için kullanılır.

Perl'deki Değişken Kapsam Belirleme'de daha fazla okuma : temel bilgiler .


16
Yerel ve küresel kelimelerin etrafından dolaşırken dikkatli olun. Uygun terimler sözcüksel ve pakettir. Perl'de gerçek global değişkenler oluşturamazsınız, ancak bazıları zaten $ _ gibi mevcuttur ve local, lexical değişkenlere (my ile yaratılmış) değil, yerelleştirilmiş değerlere (local tarafından oluşturulan) sahip paket değişkenlerine başvurur.
Chas. Owens

${^Potato}küreseldir. Nerede kullandığınızdan bağımsız olarak aynı değişkeni ifade eder.
MJD

5

Bu soru ile de ilgili olan, beni berbat eden Perl'deki sözlü bildirimlerle ilgili bazı tuzaklarla karşılaştım, bu yüzden sadece özetimi buraya ekliyorum:

1. Tanım veya beyan?

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

Çıktı var: 42. Ancak local $var = 42;, bir tanım veya bildirim olup olmadığını söyleyemedik . Ama buna ne dersiniz:

use strict;
use warnings;

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

İkinci program bir hata verecektir:

Global symbol "$var" requires explicit package name.

$vartanımlanmamıştır, bunun anlamı local $var;sadece bir bildiridir! localBir değişkeni bildirmek için kullanmadan önce değişkenin daha önce bir global değişken olarak tanımlandığından emin olun.

Ama bu neden başarısız olmaz?

use strict;
use warnings;

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

Çıktısı: var: 42.

Yıllardan Bunun nedeni $a, sıra sıra $b, bir genel değişken Perl önceden tanımlanmış olduğunu. Sıralama işlevini hatırlıyor musunuz?

2. Sözcüksel mi yoksa küresel mi?

Perl kullanmaya başlamadan önce bir C programcısıydım, bu yüzden lexical ve global değişkenler kavramı benim için basit görünüyor: sadece C'deki otomatik ve harici değişkenlere karşılık geliyor. Ama küçük farklılıklar var:

C de harici değişken, herhangi bir fonksiyon bloğunun dışında tanımlanan bir değişkendir. Diğer yandan, otomatik bir değişken, fonksiyon bloğu içinde tanımlanan bir değişkendir. Bunun gibi:

int global;

int main(void) {
    int local;
}

Perl'deyken, işler ince:

sub main {
    $var = 42;
}

&main;

print "var: $var\n";

Çıktı var: 42. $varbir fonksiyon bloğunda tanımlanmış olsa bile global bir değişkendir! Aslında Perl'de herhangi bir değişken varsayılan olarak global olarak bildirilir.

Ders her zaman use strict; use warnings;bir Perl programının başlangıcına eklemektir , bu da programcıyı sözlü değişkeni açıkça beyan etmeye zorlar, böylece verilen bazı hatalardan dolayı karışıklık yaşarız.


["Sırala [$ a ve $ b in] türünü hatırlamak" hakkında daha fazla bilgi] ( stackoverflow.com/a/26128328/1028230 ). Perl beni hayrete düşürmez.
ruffin

4

Perldoc kızımız biraz iyi tanımı vardır.

Hem bir değişken için depolama alanı ayıran hem de geçerli kapsamda kullanım için bu depolama ile basit bir ad ilişkilendiren my'imden farklı olarak, geçerli kapsamda kullanım için basit bir adı geçerli paketteki bir paket değişkeni ile ilişkilendirir. Başka bir deyişle, bizimki ile aynı kapsam belirleme kurallarına sahiptir, ancak mutlaka bir değişken oluşturmaz.


2

Bu sadece soru ile ilgili, ama ben sadece "benim" (yerel) ile kullanamazsınız "bizim" (paket) değişkenleri ile kullanabileceğiniz (bana) belirsiz bir perl sözdizimi keşfettim değişkenler.

#!/usr/bin/perl

our $foo = "BAR";

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

Çıktı:

BAR
BAZ

'Bizim' kelimemizi 'benim' olarak değiştirirseniz bu işe yaramaz.


1
Öyle değil. $ foo $ {foo} $ {'foo'} $ {"foo"} değişken atama veya kayıt silme için aynı şekilde çalışır. Takas bizim için de yukarıdaki örneği benim yaptığı işin. Muhtemelen deneyimlediğiniz şey $ foo'nun sadece $ global :: foo veya $ :: foo gibi bir paket değişkeni olarak yalnızca bizim ile tanımlananlar gibi paket globalleri için çalışmasına izin vermemeye çalışıyordu .
Cosmicnet

Sadece v5.20 kullanarak tekrar test edildi ve kesinlikle aynı çıktıyı benim ile vermiyor (iki kez BAR yazdırıyor.)
Misha Gale

1
Testim (pencerelerde): 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 Bu yüzden testimde aynı tuzağa düştüm. $ {foo} $ foo ile aynıdır, parantezler enterpolasyon yaparken kullanışlıdır. $ {"foo"} aslında ana sembol tablosu olan $ main :: {} 'a bir bakıştır, çünkü sadece paket kapsamındaki değişkenleri içerir.
Cosmicnet

1
$ {"main :: foo"}, $ {":: foo"} ve $ main :: foo, $ {"foo"} ile aynı. Steno paket duyarlıdırperl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo" bu bağlamda $ {"foo"} artık $ {"test :: foo"} 'ya eşit çalışmalardır. Sembol Tabloları ve Küreler hakkında Gelişmiş Perl programlama kitabı gibi bazı bilgiler vardır. Önceki hatam için özür dilerim.
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";

Bunu çıktılayacak:

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 

Komut dosyasını çalıştırmaya çalışırken "katı kullanın" ifadesi kullanıldığında bu hatayı alırsınız:

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

Lütfen bir tür açıklama sağlayın. Bunun gibi damping kodu nadiren uygun kabul edilir.
Scott Solmer

basit bir deyişle: Bizim (sais adı olarak), bu değişkeni komut dosyasındaki herhangi bir yerden (işlev, blok vb ...) kullanmak için değişken bir decliration'dır, varsayılan olarak her değişken (bildirilmediği takdirde) "main" e aittir. paketinde, değişkenimiz hala koddaki başka bir paketin reddedilmesinden sonra bile kullanılabilir. Bir blok veya fonksiyonda bildirilmesi durumunda "my" değişkeni, yalnızca bu blok / fonksiyonda kullanılabilir. "benim" değişkenimin bir blokta kapalı olmadığı bildirilirse, scriot'ta, kapalı bir blokta veya "bizim" değişkeni olarak herhangi bir yerde kullanılabilir, ancak paketin değişmesi durumunda kullanılamaz
Lavi Buchnik

Yukarıdaki betiğim, varsayılan olarak "ana" pakette olduğumuzu, ardından betiğin "ana" paketten (bir blokta kapalı değil) bir "bizim" değişkenini yazdırdığını, ardından bir işlevde iki "my" değişkenini bildirdiğimizi ve onları bu işlevden yazdırın. daha sonra bir fonksiyonda kullanılabileceğini göstermek için başka bir fonksiyondan bir "bizim" değişkenini yazdırırız. daha sonra paketi "değiştirildi" olarak değiştirdik (artık "ana" değil) ve "bizim" değişkenini tekrar başarılı bir şekilde yazdırıyoruz. sonra "my" değişkenini fonksiyonun dışında yazdırmaya çalıştım ve başarısız oldu. sadece "bizim" ve "benim" kullanım arasındaki farkı gösteren komut dosyası.
Lavi Buchnik

0

Sadece aşağıdaki programı kullanmaya çalışın:

#!/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";

Bu benim ve bizim arasındaki farkı açıklar. Değişkenim kıvırcık parantezlerin dışında kapsam dışına çıkıyor ve çöp toplanıyor, ancak değişkenimiz hala yaşıyor.
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;

Bu kodun ne anlama geldiğini açıklayabilir misiniz? Neden farklı ourve myfarklı? Bu örnek bunu nasıl gösteriyor?
Nathan Fellman

-1

Bir yorumlayıcının gerçekte ne olduğunu düşünelim: bu, değerleri bellekte saklayan bir kod parçasıdır ve bir programdaki talimatların bu değerlere, bu talimatlarda belirtilen adlarına göre erişmesine izin verir. Dolayısıyla, bir tercümanın büyük işi, tercümanın depoladığı değerlere erişmek için bu talimatlardaki isimleri nasıl kullanmamız gerektiğine dair kuralları şekillendirmektir.

"My" ile karşılaşıldığında, yorumlayıcı sözcüksel bir değişken oluşturur: yorumlayıcının yalnızca bir blok yürütürken ve yalnızca sözdizimsel bloğun içinden erişebileceği adlandırılmış bir değer. "Bizim" ile karşılaşıldığında, yorumlayıcı bir paket değişkeninin sözcüksel takma adını yapar: yorumlayıcının bundan sonra blok bitene kadar sözlük değişkeninin adı olarak işlemesi gereken bir adı paketin değerine bağlar. aynı ada sahip değişken.

Etkisi, daha sonra bir sözlük değişkeni kullandığınızı iddia edebilir ve paket değişkenlerinin tam niteliği üzerine 'katı kullanım' kurallarını atlayabilirsiniz. Yorumlayıcı ilk kullanıldıklarında otomatik olarak paket değişkenleri yarattığından, "bizim" kullanmanın yan etkisi de yorumlayıcının bir paket değişkeni oluşturması olabilir. Bu durumda, iki şey yaratılır: 'paketin sıkı kullanımı' (paketinin adı ve iki sütununun adı ile eklenir) tarafından istendiği gibi doğru bir şekilde tanımlanması koşuluyla, yorumlayıcının her yerden erişebileceği bir paket değişkeni ve sözcüksel takma .

Kaynaklar:

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.