【发布时间】:2010-10-25 02:36:54
【问题描述】:
我知道 Perl 中的 my 是什么。它定义了一个仅存在于定义它的块范围内的变量。 our 是做什么的?
our 与 my 有何不同?
【问题讨论】:
我知道 Perl 中的 my 是什么。它定义了一个仅存在于定义它的块范围内的变量。 our 是做什么的?
our 与 my 有何不同?
【问题讨论】:
our 与 my 有何不同,our 有何不同 做吗?
总结:
自 Perl 5 起可用,my 是一种声明非包变量的方法,即:
$package_name::variable的形式访问。另一方面,our 变量是包变量,因此自动:
$package_name::variable。使用 our 声明变量允许您预先声明变量以便在 use strict 下使用它们而无需获取错字警告或编译时错误。从 Perl 5.6 开始,它取代了过时的 use vars,它只是文件范围,而不是像 our 那样的词法范围.
例如,package main 中变量 $x 的正式限定名称是 $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; 声明了一个词法范围变量,该变量别名为编译 our 的包中的同名变量。
我曾经在 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 中预定义的全局变量。还记得sort 函数吗?
2。词法还是全局?
在开始使用 Perl 之前我是一名 C 程序员,所以词法变量和全局变量的概念对我来说似乎很简单:它只对应于 C 中的自动变量和外部变量。但有一些小的区别:
在 C 中,外部变量是在任何功能块之外定义的变量。另一方面,自动变量是在功能块内定义的变量。像这样:
int global;
int main(void) {
int local;
}
在 Perl 中,事情很微妙:
sub main {
$var = 42;
}
&main;
print "var: $var\n";
输出为var: 42。 $var 是一个全局变量,即使它是在功能块中定义的!实际上在 Perl 中,任何变量都默认声明为全局变量。
教训是始终在 Perl 程序的开头添加use strict; use warnings;,这将迫使程序员显式声明词法变量,这样我们就不会被一些理所当然的错误搞砸。
【讨论】:
my 用于局部变量,而our 用于全局变量。
更多阅读请访问 Variable Scoping in Perl: the basics。
【讨论】:
${^Potato} 是全球性的。无论你在哪里使用它,它都引用同一个变量。
一个例子:
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";
【讨论】:
让我们想想解释器实际上是什么:它是一段代码,将值存储在内存中,并让它解释的程序中的指令通过它们的名称访问这些值,这些名称在这些指令中指定。因此,解释器的主要工作是制定规则,说明我们应该如何使用这些指令中的名称来访问解释器存储的值。
在遇到“my”时,解释器创建一个词法变量:一个命名值,解释器只能在执行块时访问,并且只能从该句法块中访问。在遇到“我们的”时,解释器为包变量创建一个词法别名:它将一个名称绑定到包的值上,从那时起解释器应该将其作为词法变量的名称进行处理,直到块完成同名变量。
效果是你可以假装你正在使用一个词法变量,并绕过对包变量的完全限定的“使用严格”规则。由于解释器在第一次使用时会自动创建包变量,因此使用“我们的”的副作用也可能是解释器也会创建一个包变量。在这种情况下,创建了两件事:一个包变量,解释器可以从任何地方访问它,只要它按照“use strict”的要求正确指定(前面加上其包的名称和两个冒号),和 它的词法别名。
来源:
【讨论】:
尝试使用以下程序:
#!/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";
【讨论】:
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
如果在尝试运行脚本时使用“use strict”会失败:
Global symbol "$test1" requires explicit package name at ./check_global.pl line 24.
Execution of ./check_global.pl aborted due to compilation errors.
【讨论】:
来自 Cartman 和 Olafur 的 PerlMonks 和 PerlDoc 链接是一个很好的参考 - 以下是我的总结:
my 变量在{} 定义的单个块内的词法范围内,如果不在{}s 内,则在同一文件内。它们不能从定义在同一词法范围/块之外的包/子例程中访问。
our 变量在包/文件中的范围内,并且可以从use 或require 的任何代码访问,该包/文件 - 通过预先添加适当的命名空间来解决包之间的名称冲突。
为了完善它,local 变量是“动态”作用域的,与 my 变量的不同之处在于它们也可以从同一块内调用的子例程中访问。
【讨论】:
my 变量在同一文件中的词法范围 [...] 如果不在 {}s 中”。这对我很有用,谢谢。
#!/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 不同?这个例子是如何显示的?
这只是与问题有点相关,但我刚刚发现了一个(对我而言)晦涩难懂的 perl 语法,您可以将其与“我们的”(包)变量一起使用,而您不能将其与“我的”一起使用(局部)变量。
#!/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" 输出:barbazperl -e "my $foo = 'bar'; print $foo; ${"foo"} = 'baz'; print $foo" 输出:barbazperl -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"}。 Of Symbol Tables and Globs 有一些关于它的信息,高级 Perl 编程书也有。对不起我之前的错误。
perldoc对我们有很好的定义。
与 my 不同,它既为变量分配存储空间,又将简单名称与该存储空间相关联以在当前范围内使用,我们将简单名称与当前包中的包变量相关联,以在当前范围内使用。换句话说,our 与 my 具有相同的作用域规则,但不一定创建变量。
【讨论】:
Coping with Scoping 很好地概述了 Perl 范围规则。在正文中没有讨论our 已经足够老了。它在最后的Notes部分进行了说明。
本文讨论了包变量和动态范围,以及它们与词法变量和词法范围的区别。
【讨论】: