假设我们有这个代码,为什么它失败并显式包名称错误,因为只有在声明$value
之后才调用该函数?
use strict;
use warnings;
sub print_value{
print "\n$value";
}
my $value = 2;
print_value();
这在编译时失败:
Global symbol "$value" requires explicit package name at file.pl line 5.
Execution of file.pl aborted due to compilation errors.
这段代码非常合适:
use strict;
use warnings;
my $value = 2;
print_value();
sub print_value{
print "\n$value";
}
忽略这种编程风格或不推荐的编码风格的无用性,只关注上下文。
答案 0 :(得分:11)
这是因为scope。这就是程序中您的变量可见的位置。您的$value
是词汇变量,因为您已使用my
声明了该变量。这意味着,它存在于某个范围内(以及所有范围内)。在两个示例中,范围是整个文件(也可以称为全局范围)。
Perl分两个阶段查看您的代码。第一个是编译时,它检查语法并加载依赖项(如use
语句)。此时,它将在函数内查找$value
的可用性。
Perl会在这些地方寻找:
目前在范围内的词法(my
和our
)变量。
如果引用它的代码遵循声明,并且它与声明在同一个块中,或者嵌套在该块中,则变量在范围内(即变量是可见的)。文件本身就是一个块,并且形成了其他文件。
如果范围内有多个具有相同名称的词法变量,则最近声明的变量会掩盖其他变量。这意味着函数本身声明的变量将在函数外部使用之前使用。
my $i; # +--------- $i is in scope (visible) here
my $x; # | +------- $x is in scope (visible) here
while (...) { # | |
my $j; # | | +---- $j is in scope (visible) here
my $x; # | | +-- This different $x is in scope (visible) here
... # | v v
} # | |
sub foo { # | |
my $j; # | | +---- This different $j is in scope (visible) here
my $x; # | | +-- This third $x is in scope (visible) here
... # | v v
} # | |
... # v v
包变量
这些是全局变量(未声明,或使用use vars
声明)。
Perl会查看范围内最新“package”声明的命名空间(默认为main
),“超全局”变量除外。这是指Perl在$_
而不是当前包中查找的符号变量(如$$
,main
等)。
由于尚未声明$value
,因此Perl将其视为包变量$main::value
(因为main
是默认包)。
use strict; # | Code here will use package var $main::value
use warnings; # |
# |
sub print_value{ # |
print "\n$value"; # |
} # |
# v
my $value = 2; # | Code here will use this lexical var $value
print_value(); # v
这一切都不是因为您strict
已开启。只有必须使用my
或our
或使用完全限定名称声明变量的事实才是use strict
。
如果您没有strict
并且没有使用my
声明变量,那么您的程序就可以正常运行。在这种情况下,$value
将是一个包变量。
在您的第二个示例中,您已在子例程之前声明了$value
,因此Perl在编译时知道该范围内将有$value
可用,因此它不会抱怨。
use strict; # | Code here will use package var $main::value
use warnings; # |
# v
my $value = 2; # | Code here will use this lexical var $value
print_value(); # |
# |
sub print_value{ # |
print "\n$value"; # |
} # v
但是,更好的方法是将变量作为参数传递给print_value
。
use strict;
use warnings;
sub print_value{
my $arg = shift;
print "\n$arg";
}
my $value = 2;
print_value($value);
现在Perl看到小范围内有一个$arg
。它不知道它的价值,但它没有。在使用它之前,$value
也已经声明了。
永远不要在函数内部使用全局范围(整个文件)中的变量。始终将它们作为参数传递 1 。
以下是一些相关链接:
1)除非您想构建单身或其他类型的closure