嵌套子例程和Perl中的作用域

时间:2012-04-17 13:29:51

标签: perl scope nested subroutine

我现在写Perl很长一段时间并且总是发现新事物,我只是碰到了一些有趣的东西,我没有对它做出解释,也没有在网上找到它。

sub a {
   sub b {
     print "In B\n";
   }
}
b();

为什么我可以从其范围之外调用b()并且它有效?

我知道这是一个不好的做法,我不这样做,我使用封闭的等等这些情况,但只是看到了。

4 个答案:

答案 0 :(得分:19)

子程序在编译时存储在全局命名空间中。在您的示例中,b();main::b();的简写。要限制函数对范围的可见性,需要将匿名子例程分配给变量。

命名子程序和匿名子程序都可以形成闭包,但由于命名子程序只有嵌套它们才会被编译一次,因此它们的行为并不像人们期望的那样。

use warnings;
sub one {
    my $var = shift;
    sub two {
        print "var: $var\n";
    }
}
one("test");
two();
one("fail");
two();
__END__
output:
Variable "$var" will not stay shared at -e line 5.
var: test
var: test

在Perl中允许嵌套已命名的子例程,但这几乎肯定是代码执行错误的一个迹象。

答案 1 :(得分:7)

以下打印123

sub a {
    $b = 123;
}

a();
print $b, "\n";

那么为什么你对以下内容感到惊讶呢?

sub a {
    sub b { return 123; }
}

a();
print b(), "\n";

$b&b没有任何词汇要求。事实上,你不能要求&b是词汇(还)。

sub b { ... }

基本上是

BEGIN { *b = sub { ... }; }

其中*b$b@b,...,当然还有&b的符号表条目。这意味着subs属于包,因此可以从包内的任何地方调用,或者如果使用完全限定名称,则可以在任何地方调用(MyPackage::b())。

答案 2 :(得分:6)

在perl中创建嵌套子例程的“官方”方法是使用local关键字。例如:

sub a {
    local *b = sub {
        return 123;
    };
    return b();  # Works as expected
}

b();  # Error: "Undefined subroutine &main::b called at ..."

perldoc页面perlref有这个例子:

sub outer {
    my $x = $_[0] + 35;
    local *inner = sub { return $x * 19 };
    return $x + inner();
}

“这具有创建另一个函数本地函数的有趣效果,这在Perl中通常不受支持。”

答案 3 :(得分:2)

子程序在编译期间定义,不受作用域的影响。换句话说,它们不能真正嵌套。至少就其范围而言并非如此。在定义之后,它们将被有效地从源代码中删除。