因为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 将在范围内由最新的“包”声明的命名空间(默认为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