sno*_*kin 17 perl scope nested subroutine
我现在写Perl很长一段时间了,总是发现新的东西,我只是碰到了一些有趣的东西,我没有解释它,也没有在网上找到它.
sub a {
sub b {
print "In B\n";
}
}
b();
Run Code Online (Sandbox Code Playgroud)
为什么我可以b()
从外部调用它并且它有效?
我知道这是一个不好的做法,我不这样做,我使用闭合等这些情况,但只是看到了.
Ven*_*tsu 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
Run Code Online (Sandbox Code Playgroud)
在Perl中允许嵌套命名子例程,但几乎可以肯定这是代码执行错误的一个信号.
以下打印123
.
sub a {
$b = 123;
}
a();
print $b, "\n";
Run Code Online (Sandbox Code Playgroud)
那么为什么你对以下内容感到惊讶呢?
sub a {
sub b { return 123; }
}
a();
print b(), "\n";
Run Code Online (Sandbox Code Playgroud)
没有任何要求$b
或&b
词汇.事实上,你不能要求&b
成为词汇(还).
sub b { ... }
Run Code Online (Sandbox Code Playgroud)
基本上是
BEGIN { *b = sub { ... }; }
Run Code Online (Sandbox Code Playgroud)
这里*b
是符号表项$b
,@b
...,当然&b
.这意味着subs属于包,因此可以从包内的任何地方调用,或者如果使用完全限定名称则可以在任何地方调用(MyPackage::b()
).
在perl中创建嵌套子例程的"官方"方法是使用local
关键字.例如:
sub a {
local *b = sub {
return 123;
};
return b(); # Works as expected
}
b(); # Error: "Undefined subroutine &main::b called at ..."
Run Code Online (Sandbox Code Playgroud)
perldoc页面perlref有这个例子:
sub outer {
my $x = $_[0] + 35;
local *inner = sub { return $x * 19 };
return $x + inner();
}
Run Code Online (Sandbox Code Playgroud)
"这具有创建另一个函数本地函数的有趣效果,这在Perl中通常不受支持."