为什么子程序需要在声明其中使用的变量之后编写?

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 将在这些地方查找:

  1. 当前范围内的词法(myour)变量。

    如果引用它的代码在声明之后,并且如果它与声明位于同一块中,或者嵌套在该块中,则变量在范围内(即变量可见)。文件本身是一个块,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
    
  2. 包变量

    这些是全局变量(未声明,或使用 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。只有你 必须使用 myour 或使用完全限定名称声明变量 的事实是因为 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