我现在写Perl很长一段时间并且总是发现新事物,我只是碰到了一些有趣的东西,我没有对它做出解释,也没有在网上找到它。
sub a {
sub b {
print "In B\n";
}
}
b();
为什么我可以从其范围之外调用b()
并且它有效?
我知道这是一个不好的做法,我不这样做,我使用封闭的等等这些情况,但只是看到了。
答案 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)
子程序在编译期间定义,不受作用域的影响。换句话说,它们不能真正嵌套。至少就其范围而言并非如此。在定义之后,它们将被有效地从源代码中删除。