Apa perbedaan antara 'saya' dan 'kita' dalam Perl?

188

Saya tahu apa yang myada di Perl. Ini mendefinisikan variabel yang hanya ada dalam lingkup blok di mana ia didefinisikan. Apa yang ourharus dilakukan

Bagaimana ourberbeda dari my?

Nathan Fellman
sumber

Jawaban:

215

Pertanyaan besar: Bagaimana ourberbeda dari mydan apa yang ourlakukan?

Singkatnya:

Tersedia sejak Perl 5, myadalah cara untuk mendeklarasikan variabel non-paket, yaitu:

  • pribadi
  • baru
  • non-global
  • terpisah dari paket apa pun, sehingga variabel tidak dapat diakses dalam bentuk $package_name::variable.


Di sisi lain, ourvariabel adalah variabel paket, dan dengan demikian secara otomatis:

  • variabel global
  • jelas bukan pribadi
  • belum tentu baru
  • dapat diakses di luar paket (atau ruang lingkup leksikal) dengan namespace yang memenuhi syarat, seperti $package_name::variable.


Mendeklarasikan variabel dengan ourmemungkinkan Anda untuk mendeklarasikan variabel untuk menggunakannya di bawah use stricttanpa mendapat peringatan kesalahan ketik atau kesalahan waktu kompilasi. Sejak Perl 5.6, ia telah menggantikan yang sudah usang use vars, yang hanya mencakup file, dan tidak dibatasi secara leksikal sepertiour .

Misalnya, nama formal dan berkualitas untuk variabel $xdi dalamnya package mainadalah $main::x. Deklarasi our $xmemungkinkan Anda untuk menggunakan $xvariabel kosong tanpa penalti (yaitu, tanpa kesalahan yang dihasilkan), dalam lingkup deklarasi, ketika skrip menggunakan use strictatau use strict "vars". Lingkupnya mungkin satu, atau dua, atau lebih paket, atau satu blok kecil.

Fran Corpier
sumber
2
Jadi, bagaimana perbedaan kita dari lokal?
Nathan Fellman
17
@Nathan Fellman, localtidak membuat variabel. Itu tidak berhubungan dengan mydan oursama sekali. localsementara mencadangkan nilai variabel dan menghapus nilai saat ini.
ikegami
1
ourvariabel bukan variabel paket. Mereka bukan lingkup global, tetapi variabel cakupannya leksikal seperti myvariabel. Anda dapat melihat bahwa dalam program berikut: package Foo; our $x = 123; package Bar; say $x;. Jika Anda ingin "mendeklarasikan" variabel paket, Anda perlu menggunakannya use vars qw( $x );. our $x;mendeklarasikan variabel cakupan-leksikal yang alias ke variabel dengan nama yang sama dalam paket di mana ourdikompilasi.
ikegami
60

Tautan PerlMonks dan PerlDoc dari cartman dan Olafur adalah referensi yang bagus - di bawah ini adalah ringkasan saya di ringkasan:

myvariabel dibatasi secara leksikal dalam satu blok yang ditentukan oleh {}atau di dalam file yang sama jika tidak dalam {}s. Mereka tidak dapat diakses dari paket / subrutin yang didefinisikan di luar lingkup / blok leksikal yang sama.

ourvariabel dicakup dalam suatu paket / file dan dapat diakses dari kode apa pun useatau requirebahwa paket / file - konflik nama diselesaikan di antara paket dengan menambahkan ruang nama yang sesuai.

Untuk mengatasinya, localvariabel dibatasi secara "dinamis", berbeda dengan myvariabel yang juga dapat diakses dari subrutin yang disebut dalam blok yang sama.

bubaker
sumber
+1 untuk " myvariabel dicakup secara leksikal [...] dalam file yang sama jika tidak dalam {}s". Itu berguna bagi saya, terima kasih.
Georg
48

Sebuah contoh:

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
sumber
11

Mengatasi Pelingkupan adalah gambaran umum yang baik dari aturan pelingkupan Perl. Sudah cukup tua yang ourtidak dibahas dalam isi teks. Itu dibahas di bagian Catatan di bagian akhir.

Artikel ini berbicara tentang variabel paket dan ruang lingkup dinamis dan bagaimana hal itu berbeda dari variabel leksikal dan ruang lingkup leksikal.

daotoad
sumber
5

mydigunakan untuk variabel lokal, sedangkan ourdigunakan untuk variabel global.

Lebih banyak membaca di Variabel Pelingkupan di Perl: dasar-dasarnya .

ismail
sumber
16
Berhati-hatilah mengitari kata-kata lokal dan global. Istilah yang tepat adalah leksikal dan paket. Anda tidak dapat membuat variabel global sejati di Perl, tetapi beberapa sudah ada seperti $ _, dan lokal merujuk ke variabel paket dengan nilai lokal (dibuat oleh lokal), bukan ke variabel leksikal (dibuat dengan saya).
Chas. Owens
${^Potato}bersifat global. Ini merujuk ke variabel yang sama di mana pun Anda menggunakannya.
MJD
5

Saya pernah bertemu beberapa jebakan tentang deklarasi leksikal di Perl yang mengacaukan saya, yang juga terkait dengan pertanyaan ini, jadi saya tambahkan saja ringkasan saya di sini:

1. Definisi atau deklarasi?

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

Outputnya adalah var: 42. Namun kami tidak tahu apakah local $var = 42;itu definisi atau deklarasi. Tapi bagaimana dengan ini:

use strict;
use warnings;

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

Program kedua akan menimbulkan kesalahan:

Global symbol "$var" requires explicit package name.

$vartidak didefinisikan, yang berarti local $var;hanya deklarasi! Sebelum menggunakan localuntuk mendeklarasikan variabel, pastikan bahwa itu didefinisikan sebagai variabel global sebelumnya.

Tetapi mengapa ini tidak akan gagal?

use strict;
use warnings;

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

Outputnya adalah: var: 42.

Itu karena $a, juga $b, adalah variabel global yang telah ditentukan sebelumnya di Perl. Ingat fungsi sortir ?

2. Leksikal atau global?

Saya adalah seorang programmer C sebelum mulai menggunakan Perl, jadi konsep variabel leksikal dan global tampaknya langsung bagi saya: itu hanya sesuai dengan variabel otomatis dan eksternal dalam C. Tapi ada perbedaan kecil:

Dalam C, variabel eksternal adalah variabel yang didefinisikan di luar blok fungsi apa pun. Di sisi lain, variabel otomatis adalah variabel yang didefinisikan di dalam blok fungsi. Seperti ini:

int global;

int main(void) {
    int local;
}

Sementara di Perl, semuanya halus:

sub main {
    $var = 42;
}

&main;

print "var: $var\n";

Outputnya adalah var: 42. $varadalah variabel global bahkan jika itu didefinisikan dalam blok fungsi! Sebenarnya di Perl, variabel apa pun dinyatakan sebagai global secara default.

Pelajarannya adalah untuk selalu menambahkan use strict; use warnings;di awal program Perl, yang akan memaksa programmer untuk mendeklarasikan variabel leksikal secara eksplisit, sehingga kita tidak menjadi kacau oleh beberapa kesalahan yang diterima begitu saja.

Xu Ding
sumber
Lebih lanjut tentang ["mengingat [$ a dan $ b dalam] urutkan" di sini] ( stackoverflow.com/a/26128328/1028230 ). Perl tidak pernah berhenti, um, membuatku takjub.
ruffin
4

The perldoc memiliki definisi yang baik dari kami.

Tidak seperti saya, yang keduanya mengalokasikan penyimpanan untuk variabel dan mengaitkan nama sederhana dengan penyimpanan itu untuk digunakan dalam lingkup saat ini, kami mengaitkan nama sederhana dengan variabel paket dalam paket saat ini, untuk digunakan dalam lingkup saat ini. Dengan kata lain, kami memiliki aturan pelingkupan yang sama dengan saya, tetapi tidak harus membuat variabel.

Ólafur Waage
sumber
2

Ini hanya agak terkait dengan pertanyaan, tetapi saya baru saja menemukan sedikit sintaks perl (bagi saya) yang tidak jelas yang dapat Anda gunakan dengan variabel "kami" (paket) yang tidak dapat Anda gunakan dengan "saya" (lokal) variabel.

#!/usr/bin/perl

our $foo = "BAR";

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

Keluaran:

BAR
BAZ

Ini tidak akan berhasil jika Anda mengubah 'kami' menjadi 'saya'.

Misha Gale
sumber
1
Tidak begitu. $ foo $ {foo} $ {'foo'} $ {"foo"} semua bekerja sama untuk penugasan variabel atau dereferencing. Mengganti kita dalam contoh di atas untuk pekerjaan saya . Apa yang mungkin Anda alami adalah mencoba men-decereference $ foo sebagai variabel paket, seperti $ main :: foo atau $ :: foo yang hanya akan berfungsi untuk paket global, seperti yang didefinisikan dengan kami .
Cosmicnet
Hanya diuji ulang menggunakan v5.20, dan itu pasti tidak memberikan output yang sama dengan saya (itu mencetak BAR dua kali.)
Misha Gale
1
Tes saya (pada 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 Jadi dalam pengujian saya, saya jatuh ke dalam perangkap yang sama. $ {foo} sama dengan $ foo, tanda kurung berguna saat interpolasi. $ {"foo"} sebenarnya adalah tampilan hingga $ main :: {} yang merupakan tabel simbol utama, karena hanya berisi variabel scoped paket.
Cosmicnet
1
$ {"main :: foo"}, $ {":: foo"}, dan $ main :: foo sama dengan $ {"foo"}. Singkatannya adalah paket yang sensitif perl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo", karena dalam konteks ini $ {"foo"} sekarang sama dengan $ {"test :: foo"}. Tabel Simbol dan Glob memiliki beberapa informasi tentang itu, seperti halnya buku pemrograman Advanced Perl. Maaf atas kesalahan saya sebelumnya.
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";

Akan Keluarkan ini:

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 

Jika menggunakan "gunakan ketat" akan mendapatkan kegagalan ini saat mencoba menjalankan skrip:

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
sumber
Harap berikan semacam penjelasan. Kode pembuangan seperti ini jarang dianggap tepat.
Scott Solmer
dalam kata-kata sederhana: Kami (sebagai nama sais) adalah deklarasi variabel untuk menggunakan variabel itu dari tempat mana pun dalam skrip (fungsi, blok dll ...), setiap variabel secara default (jika tidak dideklarasikan) milik "main" paket, variabel kami masih dapat digunakan bahkan setelah mendeklarasikan paket lain dalam skrip. Variabel "saya" dalam hal dinyatakan dalam blok atau fungsi, dapat digunakan dalam blok / fungsi itu saja. dalam kasus "saya" variabel dinyatakan tidak ditutup dalam blok, itu dapat digunakan di mana saja di scriot, di blok tertutup juga atau dalam fungsi sebagai variabel "kami", tetapi tidak dapat digunakan dalam paket kasus berubah
Lavi Buchnik
Skrip saya di atas menunjukkan bahwa secara default kita berada dalam paket "utama", lalu skrip tersebut mencetak variabel "kita" dari paket "utama" (tidak ditutup dalam satu blok), kemudian kita mendeklarasikan dua variabel "saya" dalam suatu fungsi dan cetak mereka dari fungsi itu. lalu kita mencetak variabel "kita" dari fungsi lain untuk menunjukkannya dapat digunakan dalam suatu fungsi. lalu kita mengubah paket menjadi "berubah" (bukan "utama" lagi), dan kita mencetak lagi variabel "kita" dengan sukses. kemudian mencoba mencetak variabel "saya" di luar fungsi dan gagal. script hanya menunjukkan perbedaan antara penggunaan "kami" dan "saya".
Lavi Buchnik
0

Coba gunakan program berikut:

#!/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
sumber
Ini menjelaskan perbedaan antara saya dan kami. Variabel saya keluar dari ruang lingkup di luar kurung kurawal dan dikumpulkan sampah tetapi variabel kami masih hidup.
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;
tidak ada
sumber
Bisakah Anda menjelaskan apa yang ingin ditunjukkan oleh kode ini? Mengapa ourdan myberbeda? Bagaimana contoh ini menunjukkannya?
Nathan Fellman
-1

Mari kita pikirkan apa sebenarnya juru bahasa: itu adalah sepotong kode yang menyimpan nilai dalam memori dan membiarkan instruksi dalam program yang diinterpretasikan mengakses nilai-nilai tersebut dengan nama mereka, yang ditentukan di dalam instruksi ini. Jadi, pekerjaan besar seorang juru bahasa adalah untuk membentuk aturan bagaimana kita harus menggunakan nama-nama dalam instruksi tersebut untuk mengakses nilai-nilai yang disimpan oleh juru bahasa tersebut.

Saat menemukan "saya", interpreter menciptakan variabel leksikal: nilai bernama yang hanya dapat diakses oleh interpreter ketika mengeksekusi blok, dan hanya dari dalam blok sintaksis itu. Pada pertemuan "kita", penerjemah membuat alias leksikal dari variabel paket: ia mengikat nama, yang oleh penerjemah diharapkan sejak saat itu untuk diproses sebagai nama variabel leksikal, sampai blok selesai, dengan nilai paket variabel dengan nama yang sama.

Efeknya adalah bahwa Anda kemudian dapat berpura-pura bahwa Anda menggunakan variabel leksikal dan mengabaikan aturan 'gunakan ketat' pada kualifikasi penuh variabel paket. Karena penerjemah secara otomatis membuat variabel paket ketika mereka pertama kali digunakan, efek samping dari menggunakan "kami" juga mungkin bahwa penerjemah menciptakan variabel paket juga. Dalam hal ini, dua hal dibuat: variabel paket, yang dapat diakses oleh penerjemah dari mana-mana, asalkan ditunjuk dengan tepat seperti yang diminta oleh 'use strict' (diawali dengan nama paketnya dan dua titik dua), dan alias leksikalnya.

Sumber:

Evgeniy
sumber