17

我写 Perl 已经有一段时间了,总是在发现新事物,我只是遇到了一些有趣的东西,我没有解释,也没有在网上找到它。

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

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

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

4

4 回答 4

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 中允许嵌套命名子例程,但这几乎可以肯定是代码执行错误的标志。

于 2012-04-17T13:49:22.543 回答
9

在 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 通常不支持这种功能。”

于 2013-11-26T00:40:29.403 回答
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的符号表条目在哪里,当然还有。这意味着 subs 属于包,因此可以从包内的任何地方调用,或者如果使用了它们的完全限定名(),则可以在任何地方调用。$b@b&bMyPackage::b()

于 2012-04-17T15:58:09.980 回答
2

子程序是在编译时定义的,不受作用域的影响。换句话说,它们不能真正嵌套。至少就他们自己的范围而言不是。在被定义之后,它们被有效地从源代码中删除。

于 2012-04-17T13:43:22.493 回答