私はかなり長い間 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()
サブルーチンはコンパイル時に定義され、スコープの影響を受けません。つまり、真にネストすることはできません。少なくとも、彼ら自身の範囲に関する限りではありません。定義後、それらはソース コードから効果的に削除されます。