Tôi biết những gì my
trong Perl. Nó định nghĩa một biến chỉ tồn tại trong phạm vi của khối mà nó được xác định. Không gì our
làm gì?
Làm thế nào our
khác nhau my
?
Tôi biết những gì my
trong Perl. Nó định nghĩa một biến chỉ tồn tại trong phạm vi của khối mà nó được xác định. Không gì our
làm gì?
Làm thế nào our
khác nhau my
?
Câu trả lời:
Câu hỏi tuyệt vời: Làm thế nào our
khác với my
và làm gìour
làm gì?
Tóm tắt:
Có sẵn kể từ Perl 5, my
là một cách để khai báo các biến không phải là gói, đó là:
$package_name::variable
.Mặt khác, our
các biến là các biến gói và do đó tự động:
$package_name::variable
.Khai báo một biến với our
cho phép bạn khai báo trước các biến để sử dụng chúng theo use strict
mà không nhận được cảnh báo lỗi chính tả hoặc lỗi thời gian biên dịch. Kể từ Perl 5.6, nó đã thay thế lỗi thời use vars
, chỉ có phạm vi tệp và không có phạm vi từ vựng như hiện tại our
.
Ví dụ, tên chính thức, đủ điều kiện cho biến $x
bên trong package main
là $main::x
. Khai báo our $x
cho phép bạn sử dụng $x
biến trần mà không bị phạt (nghĩa là không có lỗi dẫn đến), trong phạm vi khai báo, khi tập lệnh sử dụng use strict
hoặc use strict "vars"
. Phạm vi có thể là một, hoặc hai hoặc nhiều gói hoặc một khối nhỏ.
local
không tạo biến. Nó không liên quan đến my
và our
tất cả. local
tạm thời sao lưu giá trị của biến và xóa giá trị hiện tại của nó.
our
biến không phải là biến gói. Chúng không có phạm vi toàn cầu, nhưng các biến có phạm vi từ vựng giống như my
các biến. Bạn có thể thấy rằng trong chương trình sau : package Foo; our $x = 123; package Bar; say $x;
. Nếu bạn muốn "khai báo" một biến gói, bạn cần sử dụng use vars qw( $x );
. our $x;
khai báo một biến có phạm vi từ vựng được đặt bí danh cho biến cùng tên trong gói trong đó gói our
được biên dịch.
Các liên kết PerlMonks và PerlDoc từ cartman và Olafur là một tài liệu tham khảo tuyệt vời - dưới đây là bản tóm tắt của tôi:
my
các biến được phạm vi từ vựng trong một khối duy nhất được xác định bởi {}
hoặc trong cùng một tệp nếu không tính bằng {}
s. Chúng không thể truy cập được từ các gói / chương trình con được xác định bên ngoài cùng phạm vi / khối từ vựng.
our
các biến được đặt trong phạm vi một gói / tệp và có thể truy cập được từ bất kỳ mã nào use
hoặc require
xung đột tên / tệp đó được giải quyết giữa các gói bằng cách thêm vào không gian tên thích hợp.
Chỉ cần làm tròn nó ra, local
các biến có phạm vi "động", khác với my
các biến ở chỗ chúng cũng có thể truy cập được từ các chương trình con được gọi trong cùng một khối.
my
các biến được đặt trong phạm vi từ vựng [...] trong cùng một tệp nếu không tính bằng {}
s". Điều đó rất hữu ích cho tôi, cảm ơn.
Một ví dụ:
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";
Đối phó với Scoping là một tổng quan tốt về các quy tắc phạm vi Perl. Nó đủ cũ mà our
không được thảo luận trong phần thân của văn bản. Nó được giải quyết trong phần Ghi chú ở cuối.
Bài báo nói về các biến gói và phạm vi động và cách khác với các biến từ vựng và phạm vi từ vựng.
my
được sử dụng cho các biến cục bộ, trong khi our
được sử dụng cho các biến toàn cục.
Đọc thêm tại Biến phạm vi trong Perl: những điều cơ bản .
${^Potato}
là toàn cầu. Nó đề cập đến cùng một biến bất kể bạn sử dụng nó ở đâu.
Tôi đã từng gặp một số cạm bẫy về các tuyên bố từ vựng trong Perl đã làm tôi bối rối, điều này cũng liên quan đến câu hỏi này, vì vậy tôi chỉ cần thêm tóm tắt của tôi ở đây:
1. Định nghĩa hay khai báo?
local $var = 42;
print "var: $var\n";
Đầu ra là var: 42
. Tuy nhiên, chúng tôi không thể biết nếu local $var = 42;
là một định nghĩa hoặc tuyên bố. Nhưng làm thế nào về điều này:
use strict;
use warnings;
local $var = 42;
print "var: $var\n";
Chương trình thứ hai sẽ đưa ra một lỗi:
Global symbol "$var" requires explicit package name.
$var
không được xác định, có nghĩa local $var;
chỉ là một tuyên bố! Trước khi sử dụng local
để khai báo một biến, hãy đảm bảo rằng nó được định nghĩa là biến toàn cục trước đó.
Nhưng tại sao điều này sẽ không thất bại?
use strict;
use warnings;
local $a = 42;
print "var: $a\n";
Đầu ra là : var: 42
.
Đó là bởi vì $a
, cũng như $b
, là một biến toàn cục được xác định trước trong Perl. Ghi nhớ chức năng sắp xếp ?
2. Từ điển hay toàn cầu?
Tôi là một lập trình viên C trước khi bắt đầu sử dụng Perl, vì vậy khái niệm về các biến từ vựng và toàn cầu có vẻ đơn giản với tôi: nó chỉ tương ứng với các biến tự động và biến ngoài trong C. Nhưng có một số khác biệt nhỏ:
Trong C, một biến ngoài là một biến được định nghĩa bên ngoài bất kỳ khối chức năng nào. Mặt khác, một biến tự động là một biến được xác định bên trong một khối chức năng. Như thế này:
int global;
int main(void) {
int local;
}
Trong khi ở Perl, mọi thứ thật tinh tế:
sub main {
$var = 42;
}
&main;
print "var: $var\n";
Đầu ra là var: 42
. $var
là một biến toàn cục ngay cả khi nó được xác định trong một khối chức năng! Trên thực tế trong Perl, bất kỳ biến nào được khai báo là toàn cục theo mặc định.
Bài học là luôn luôn bổ sung use strict; use warnings;
vào đầu chương trình Perl, điều này sẽ buộc lập trình viên phải khai báo biến từ vựng một cách rõ ràng, để chúng ta không bị nhầm lẫn bởi một số sai lầm đã xảy ra.
Các perldoc có một định nghĩa tốt của chúng tôi.
Không giống như tôi, cả hai phân bổ lưu trữ cho một biến và liên kết một tên đơn giản với lưu trữ đó để sử dụng trong phạm vi hiện tại, chúng tôi liên kết một tên đơn giản với một biến gói trong gói hiện tại, để sử dụng trong phạm vi hiện tại. Nói cách khác, chúng tôi có các quy tắc phạm vi giống như của tôi, nhưng không nhất thiết phải tạo một biến.
Điều này chỉ liên quan đến câu hỏi, nhưng tôi vừa phát hiện ra một cú pháp tối nghĩa (với tôi) tối nghĩa mà bạn có thể sử dụng với các biến "của chúng tôi" (gói) mà bạn không thể sử dụng với "của tôi" (cục bộ) biến.
#!/usr/bin/perl
our $foo = "BAR";
print $foo . "\n";
${"foo"} = "BAZ";
print $foo . "\n";
Đầu ra:
BAR
BAZ
Điều này sẽ không hoạt động nếu bạn thay đổi 'của chúng tôi' thành 'của tôi'.
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
Vì vậy, trong thử nghiệm của tôi, tôi đã rơi vào cùng một cái bẫy. $ {foo} giống như $ foo, dấu ngoặc hữu ích khi nội suy. $ {"foo"} thực sự là một tra cứu tới $ main :: {} là bảng ký hiệu chính, vì như vậy chỉ chứa các biến trong phạm vi gói.
perl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"
công việc nhạy cảm , vì trong bối cảnh này $ {"foo"} hiện bằng $ {"test :: foo"}. Of Symbol Bảng và Globs có một số thông tin về nó, cũng như cuốn sách lập trình Advanced Perl. Xin lỗi vì sai lầm trước đây của tôi.
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";
Sẽ xuất ra điều này:
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
Trong trường hợp sử dụng "sử dụng nghiêm ngặt" sẽ gặp lỗi này trong khi cố gắng chạy tập lệnh:
Global symbol "$test1" requires explicit package name at ./check_global.pl line 24.
Execution of ./check_global.pl aborted due to compilation errors.
Chỉ cần cố gắng sử dụng chương trình sau đây:
#!/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
và my
khác nhau? Làm thế nào để ví dụ này cho thấy nó?
Chúng ta hãy nghĩ trình thông dịch thực sự là gì: đó là một đoạn mã lưu trữ các giá trị trong bộ nhớ và cho phép các hướng dẫn trong một chương trình mà nó diễn giải truy cập các giá trị đó bằng tên của chúng, được chỉ định trong các hướng dẫn này. Vì vậy, công việc lớn của một thông dịch viên là định hình các quy tắc về cách chúng ta nên sử dụng tên trong các hướng dẫn đó để truy cập các giá trị mà trình thông dịch lưu trữ.
Khi gặp "của tôi", trình thông dịch tạo ra một biến từ vựng: một giá trị được đặt tên mà trình thông dịch chỉ có thể truy cập trong khi nó thực thi một khối và chỉ từ trong khối cú pháp đó. Khi gặp "của chúng tôi", trình thông dịch tạo một bí danh từ vựng của biến gói: nó liên kết một tên, mà trình thông dịch được cho là từ đó trở thành xử lý như một tên biến từ vựng, cho đến khi khối kết thúc, với giá trị của gói biến có cùng tên.
Hiệu quả là sau đó bạn có thể giả vờ rằng bạn đang sử dụng một biến từ vựng và bỏ qua các quy tắc 'sử dụng nghiêm ngặt' về trình độ đầy đủ của các biến gói. Do trình thông dịch tự động tạo các biến gói khi chúng được sử dụng lần đầu tiên, nên tác dụng phụ của việc sử dụng "của chúng tôi" cũng có thể là trình thông dịch cũng tạo ra một biến gói. Trong trường hợp này, hai thứ được tạo ra: một biến gói, mà trình thông dịch có thể truy cập từ mọi nơi, miễn là nó được chỉ định đúng theo yêu cầu của 'userict' (được đặt trước tên của gói và hai dấu hai chấm) và bí danh từ vựng của nó.
Nguồn: