ฉันรู้ว่าสิ่งที่my
อยู่ใน Perl มันกำหนดตัวแปรที่มีอยู่เฉพาะในขอบเขตของบล็อกที่มีการกำหนดไว้ อะไรour
ทำอย่างไร
วิธีการที่ไม่our
แตกต่างจากmy
?
ฉันรู้ว่าสิ่งที่my
อยู่ใน Perl มันกำหนดตัวแปรที่มีอยู่เฉพาะในขอบเขตของบล็อกที่มีการกำหนดไว้ อะไรour
ทำอย่างไร
วิธีการที่ไม่our
แตกต่างจากmy
?
คำตอบ:
คำถามยอดเยี่ยม: our
แตกต่างจากmy
และour
ทำอย่างไร
สรุป:
มีให้ตั้งแต่ Perl 5 my
เป็นวิธีการประกาศตัวแปรที่ไม่ใช่แพ็คเกจซึ่ง ได้แก่ :
$package_name::variable
เข้าถึงได้ในรูปแบบของในทางตรงกันข้ามour
ตัวแปรเป็นตัวแปรแพ็คเกจและโดยอัตโนมัติ:
$package_name::variable
ที่ผ่านการรับรองเป็นการประกาศตัวแปรด้วยour
อนุญาตให้คุณประกาศตัวแปรuse strict
ล่วงหน้าเพื่อใช้งานภายใต้โดยไม่ได้รับคำเตือนที่พิมพ์ผิดหรือข้อผิดพลาดในการคอมไพล์ ตั้งแต่ Perl 5.6 มันได้เข้ามาแทนที่ล้าสมัยuse vars
ซึ่งเป็นเพียงไฟล์ขอบเขตและไม่กำหนดขอบเขต lexically our
ตามที่เป็นอยู่
ยกตัวอย่างเช่นอย่างเป็นทางการชื่อที่มีคุณภาพสำหรับตัวแปร$x
ภายในคือpackage main
$main::x
ประกาศour $x
ช่วยให้คุณใช้เปลือย$x
ตัวแปรโดยไม่มีการลงโทษ (เช่นโดยไม่มีข้อผิดพลาดที่เกิด) อยู่ในขอบเขตของการประกาศเมื่อใช้สคริปต์หรือuse strict
use strict "vars"
ขอบเขตอาจเป็นแพ็คเกจหนึ่งหรือสองแพคเกจขึ้นไปหรือหนึ่งบล็อคเล็ก
local
ไม่ได้สร้างตัวแปร มันไม่เกี่ยวข้องกับmy
และour
ทั้งหมด local
สำรองค่าตัวแปรชั่วคราวและล้างค่าปัจจุบัน
our
ตัวแปรไม่ใช่ตัวแปรของแพ็คเกจ พวกเขาไม่ได้กำหนดขอบเขตทั่วโลก แต่ตัวแปรที่มีการกำหนดขอบเขตแบบย่อเหมือนกับmy
ตัวแปร package Foo; our $x = 123; package Bar; say $x;
คุณจะเห็นว่าในโปรแกรมดังต่อไปนี้: หากคุณต้องการที่จะ "ประกาศ" use vars qw( $x );
ตัวแปรแพคเกจที่คุณจำเป็นต้องใช้ our $x;
ประกาศตัวแปรที่กำหนดขอบเขตแบบ lexically ซึ่งเป็นนามแฝงกับตัวแปรที่มีชื่อเดียวกันในแพ็กเกจที่our
คอมไพล์แล้ว
ลิงก์ PerlMonks และ PerlDoc จาก cartman และ Olafur เป็นข้อมูลอ้างอิงที่ดีมาก - ด้านล่างเป็นข้อสรุปของฉัน:
my
ตัวแปรถูกกำหนดขอบเขตโดยละเอียดภายในบล็อกเดียวที่กำหนดโดย{}
หรือภายในไฟล์เดียวกันหากไม่อยู่ใน{}
s ไม่สามารถเข้าถึงได้จากแพ็คเกจ / รูทีนย่อยที่กำหนดไว้ภายนอกขอบเขต / บล็อกของคำศัพท์เดียวกัน
our
ตัวแปรถูกกำหนดขอบเขตภายในแพ็กเกจ / ไฟล์และสามารถเข้าถึงได้จากโค้ดใด ๆ ที่use
หรือrequire
ความขัดแย้งของแพ็กเกจ / ไฟล์ - ชื่อถูกแก้ไขระหว่างแพ็กเกจโดยการเพิ่มเนมสเปซที่เหมาะสม
เพียงเพื่อปัดเศษlocal
ตัวแปรจะถูกกำหนดขอบเขตแบบไดนามิกแตกต่างจากmy
ตัวแปรที่สามารถเข้าถึงได้จากรูทีนย่อยที่เรียกว่าภายในบล็อกเดียวกัน
my
ตัวแปรถูกกำหนดขอบเขตโดยเล็ก [... ] ภายในไฟล์เดียวกันหากไม่อยู่ใน{}
s" นั่นเป็นประโยชน์สำหรับฉันขอบคุณ
ตัวอย่าง:
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";
การรับมือกับการกำหนดขอบเขตเป็นภาพรวมที่ดีของกฎการกำหนดขอบเขต Perl อายุมากพอที่our
จะไม่กล่าวถึงในเนื้อความของเนื้อหา มันถูกแก้ไขในNotesส่วนท้าย
บทความนี้กล่าวถึงตัวแปรแพ็กเกจและขอบเขตไดนามิกและความแตกต่างจากตัวแปรคำศัพท์และขอบเขตคำศัพท์
my
ใช้สำหรับตัวแปรโลคัลขณะที่our
ใช้สำหรับตัวแปรโกลบอล
เพิ่มเติมอ่านมากกว่าที่ตัวแปรกำหนดขอบเขตใน Perl: พื้นฐาน
${^Potato}
เป็นสากล มันหมายถึงตัวแปรเดียวกันโดยไม่คำนึงถึงตำแหน่งที่คุณใช้
ฉันเคยพบกับข้อผิดพลาดบางประการเกี่ยวกับการประกาศคำศัพท์ใน Perl ที่ทำให้ฉันสับสนซึ่งเกี่ยวข้องกับคำถามนี้ด้วยดังนั้นฉันจึงเพิ่มบทสรุปของฉันที่นี่:
1. คำจำกัดความหรือประกาศ?
local $var = 42;
print "var: $var\n";
var: 42
เอาท์พุทเป็น อย่างไรก็ตามเราไม่สามารถบอกได้ว่าlocal $var = 42;
เป็นคำจำกัดความหรือคำประกาศ แต่วิธีนี้:
use strict;
use warnings;
local $var = 42;
print "var: $var\n";
โปรแกรมที่สองจะเกิดข้อผิดพลาด:
Global symbol "$var" requires explicit package name.
$var
ไม่ได้กำหนดไว้ซึ่งหมายความว่า local $var;
เป็นเพียงการประกาศ! ก่อนที่จะใช้local
เพื่อประกาศตัวแปรตรวจสอบให้แน่ใจว่าได้กำหนดเป็นตัวแปรกลางก่อนหน้านี้
แต่ทำไมสิ่งนี้ถึงไม่ล้มเหลว
use strict;
use warnings;
local $a = 42;
print "var: $a\n";
ผลลัพธ์คือ: var: 42
.
นั่นเป็นเพราะ$a
เช่นเดียวกับ$b
เป็นตัวแปรทั่วโลกที่กำหนดไว้ล่วงหน้าใน Perl จำฟังก์ชั่นการจัดเรียง ?
2. คำศัพท์หรือทั่วโลก?
ฉันเป็นโปรแกรมเมอร์ C ก่อนที่จะเริ่มใช้ Perl ดังนั้นแนวคิดเกี่ยวกับตัวแปรคำศัพท์และทั่วโลกดูเหมือนจะตรงไปตรงมากับฉัน: มันสอดคล้องกับตัวแปร auto และตัวแปรภายนอกใน C แต่มีความแตกต่างเล็กน้อย:
ใน C ตัวแปรภายนอกเป็นตัวแปรที่กำหนดไว้ภายนอกบล็อกฟังก์ชันใด ๆ ในทางกลับกันตัวแปรอัตโนมัติเป็นตัวแปรที่กำหนดไว้ภายในบล็อกฟังก์ชั่น แบบนี้:
int global;
int main(void) {
int local;
}
ในขณะที่ Perl สิ่งต่าง ๆ :
sub main {
$var = 42;
}
&main;
print "var: $var\n";
var: 42
เอาท์พุทเป็น $var
เป็นตัวแปรทั่วโลกแม้ว่าจะกำหนดไว้ในบล็อกฟังก์ชัน! ที่จริงแล้วใน Perl ตัวแปรใด ๆ จะถูกประกาศเป็นโกลบอลตามค่าเริ่มต้น
บทเรียนคือการเพิ่มuse strict; use warnings;
ที่จุดเริ่มต้นของโปรแกรม Perl ซึ่งจะบังคับให้โปรแกรมเมอร์ประกาศตัวแปรศัพท์อย่างชัดเจนเพื่อที่เราจะไม่ได้รับความผิดพลาดจากความผิดพลาดบางอย่างที่ได้รับ
perldocมีความหมายที่ดีของเรา
ต่างจากฉันซึ่งทั้งสองจัดสรรที่เก็บข้อมูลสำหรับตัวแปรและเชื่อมโยงชื่อแบบง่ายกับที่เก็บข้อมูลนั้นเพื่อใช้ภายในขอบเขตปัจจุบันเราเชื่อมโยงชื่อแบบง่ายกับตัวแปรแพคเกจในแพ็คเกจปัจจุบันเพื่อใช้ภายในขอบเขตปัจจุบัน กล่าวอีกนัยหนึ่งเรามีกฎการกำหนดขอบเขตเดียวกับของฉัน แต่ไม่จำเป็นต้องสร้างตัวแปร
สิ่งนี้เกี่ยวข้องกับคำถามเพียงเล็กน้อย แต่ฉันเพิ่งค้นพบไวยากรณ์ perl ที่ไม่ชัดเจนซึ่งคุณสามารถใช้กับตัวแปร "ของเรา" (แพ็คเกจ) ที่คุณไม่สามารถใช้กับ "my" (local) ตัวแปร
#!/usr/bin/perl
our $foo = "BAR";
print $foo . "\n";
${"foo"} = "BAZ";
print $foo . "\n";
เอาท์พุท:
BAR
BAZ
สิ่งนี้จะไม่ทำงานหากคุณเปลี่ยน 'ของเรา' เป็น 'ของฉัน'
perl -e "my $foo = 'bar'; print $foo; ${foo} = 'baz'; pr int $foo"
เอาท์พุท: barbaz
perl -e "my $foo = 'bar'; print $foo; ${"foo"} = 'baz'; print $foo"
เอาท์พุท: barbaz
perl -e "my $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"
เอาท์พุท: barbar
ดังนั้นในการทดสอบของฉันฉันจะตกหลุมพรางเดียวกัน $ {foo} เหมือนกันกับ $ foo วงเล็บจะมีประโยชน์เมื่อทำการแก้ไข $ {"foo"} จริง ๆ แล้วค้นหาสูงสุดถึง $ main :: {} ซึ่งเป็นตารางสัญลักษณ์หลักเช่นนั้นจะมีเฉพาะตัวแปรที่กำหนดขอบเขตแพ็คเกจเท่านั้น
perl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"
งานที่ละเอียดอ่อนของแพคเกจเช่นในบริบทนี้ $ {"foo"} ตอนนี้เท่ากับ $ {"test :: foo"} Symbol Tables and Globsมีข้อมูลบางอย่างเกี่ยวกับมันเช่นเดียวกับหนังสือการเขียนโปรแกรม Perl ขั้นสูง ขออภัยในความผิดพลาดครั้งก่อน
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";
จะเอาท์พุทนี้:
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
ในกรณีที่ใช้ "ใช้เข้มงวด" จะได้รับความล้มเหลวนี้ในขณะที่พยายามเรียกใช้สคริปต์:
Global symbol "$test1" requires explicit package name at ./check_global.pl line 24.
Execution of ./check_global.pl aborted due to compilation errors.
เพียงลองใช้โปรแกรมต่อไปนี้:
#!/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
และmy
แตกต่างกันอย่างไร ตัวอย่างนี้แสดงให้เห็นอย่างไร
ให้เราคิดว่าผู้แปลคืออะไร: เป็นชิ้นส่วนของรหัสที่เก็บค่าในหน่วยความจำและให้คำแนะนำในโปรแกรมที่ตีความการเข้าถึงค่าเหล่านั้นด้วยชื่อซึ่งระบุไว้ในคำแนะนำเหล่านี้ ดังนั้นงานใหญ่ของล่ามคือจัดทำกฎของวิธีที่เราควรใช้ชื่อในคำแนะนำเหล่านั้นเพื่อเข้าถึงค่าที่ล่ามเก็บ
เมื่อเผชิญหน้ากับ "my" ล่ามจะสร้างตัวแปรศัพท์: ค่าที่มีชื่อที่ล่ามสามารถเข้าถึงได้เฉพาะในขณะที่มันเรียกใช้บล็อกและจากภายในวากยสัมพันธ์บล็อกนั้น ในการเผชิญหน้ากับ "ของเรา" ล่ามจะสร้างนามแฝงศัพท์ของตัวแปรแพ็กเกจ: มันผูกชื่อซึ่งล่ามควรจากนั้นไปประมวลผลเป็นชื่อของตัวแปรศัพท์จนกระทั่งบล็อกเสร็จแล้วถึงค่าของแพคเกจ ตัวแปรที่มีชื่อเดียวกัน
ผลกระทบคือคุณสามารถแสร้งทำเป็นว่าคุณกำลังใช้ตัวแปรศัพท์และข้ามกฎของ 'การใช้ที่เข้มงวด' กับคุณสมบัติทั้งหมดของตัวแปรแพคเกจ เนื่องจากล่ามจะสร้างตัวแปรแพ็กเกจโดยอัตโนมัติเมื่อมีการใช้งานครั้งแรกผลข้างเคียงของการใช้ "ของเรา" อาจเป็นไปได้ว่าล่ามจะสร้างตัวแปรแพ็กเกจด้วยเช่นกัน ในกรณีนี้จะมีการสร้างสองสิ่ง: ตัวแปรแพ็กเกจซึ่งล่ามสามารถเข้าถึงได้จากทุกที่หากมีการกำหนดอย่างถูกต้องตามที่ร้องขอโดย 'ใช้เข้มงวด' (ต่อท้ายด้วยชื่อแพ็คเกจและโคลอนสองตัว) และนามแฝงศัพท์
แหล่งที่มา: