我写 Perl 已经有一段时间了,总是在发现新事物,我只是遇到了一些有趣的东西,我没有解释,也没有在网上找到它。
sub a {
sub b {
print "In B\n";
}
}
b();
为什么我可以b()
从它的范围之外调用它并且它有效?
我知道这样做是一种不好的做法,但我不这样做,我在这些情况下使用封闭等,但只是看到了这一点。
我写 Perl 已经有一段时间了,总是在发现新事物,我只是遇到了一些有趣的东西,我没有解释,也没有在网上找到它。
sub a {
sub b {
print "In B\n";
}
}
b();
为什么我可以b()
从它的范围之外调用它并且它有效?
我知道这样做是一种不好的做法,但我不这样做,我在这些情况下使用封闭等,但只是看到了这一点。
子例程在编译时存储在全局命名空间中。在您的示例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 中允许嵌套命名子例程,但这几乎可以肯定是代码执行错误的标志。
在 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 通常不支持这种功能。”
以下打印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
&b
MyPackage::b()
子程序是在编译时定义的,不受作用域的影响。换句话说,它们不能真正嵌套。至少就他们自己的范围而言不是。在被定义之后,它们被有效地从源代码中删除。