为什么子程序需要在声明其中使用的变量之后编写?
Why subroutine needs to be written after the declaration of variables used in it?
假设我们有这段代码,为什么它会因显式包名称错误而失败,因为该函数仅在 $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";
}
忽略这种编程风格的无用性或已弃用的编码风格,只关注上下文。
是因为scope。这就是您的程序中您的变量可见的地方。你的 $value
是一个 词法 变量,因为你用 my
声明了它。这意味着,它存在于某个范围内(以及所有低于该范围的范围)。在您的两个示例中,范围都是整个文件(也可以称为 全局范围 )。
Perl 分两个阶段查看您的代码。第一个是 编译时间 ,它检查语法并加载依赖项(如 use
语句)。此时,它会在函数内部寻找$value
的可用性。
Perl 将在这些地方查找:
当前范围内的词法(my
和 our
)变量。
如果引用它的代码在声明之后,并且如果它与声明位于同一块中,或者嵌套在该块中,则变量在范围内(即变量可见)。文件本身是一个块,curlies 形成其他块。
如果范围内有多个同名的词法变量,最近声明的变量会掩盖其他变量。这意味着在函数本身中声明的变量将在函数外部的变量之前使用。
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
)最近的 "package" 声明的名称空间中查找,"super-global" 变量除外。这是指 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
None 是因为您打开了 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
假设我们有这段代码,为什么它会因显式包名称错误而失败,因为该函数仅在 $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";
}
忽略这种编程风格的无用性或已弃用的编码风格,只关注上下文。
是因为scope。这就是您的程序中您的变量可见的地方。你的 $value
是一个 词法 变量,因为你用 my
声明了它。这意味着,它存在于某个范围内(以及所有低于该范围的范围)。在您的两个示例中,范围都是整个文件(也可以称为 全局范围 )。
Perl 分两个阶段查看您的代码。第一个是 编译时间 ,它检查语法并加载依赖项(如 use
语句)。此时,它会在函数内部寻找$value
的可用性。
Perl 将在这些地方查找:
当前范围内的词法(
my
和our
)变量。如果引用它的代码在声明之后,并且如果它与声明位于同一块中,或者嵌套在该块中,则变量在范围内(即变量可见)。文件本身是一个块,curlies 形成其他块。
如果范围内有多个同名的词法变量,最近声明的变量会掩盖其他变量。这意味着在函数本身中声明的变量将在函数外部的变量之前使用。
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
)最近的 "package" 声明的名称空间中查找,"super-global" 变量除外。这是指 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
None 是因为您打开了 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