2

次のコードを入力して実行すると、<FONT COLOR ='foo'></FONT>と入力されます。myただし、ループ変数( )に追加するとfor my $name (@colors)、期待される<FONT COLOR ='red'></FONT>が入力されます。誰かが理由を説明できますか?

@colors = qw(red blue green yellow orange purple violet);
$name = 'foo';
for $name (@colors) {
  no strict 'refs';
  *$name = sub { "<FONT COLOR='$name'></FONT>" };
}
print red();
4

3 に答える 3

3

あなたのループでは、いくつかのサブを作成します。これらのサブルーチンは、それらが作成されたコンテキストのすべての変数を見ることができます。

ローカル/グローバル変数を使用すると、サブルーチンは常に最新の値を参照します (文字列への変数の補間は、コンパイル時または「定義時」には発生しませんが、サブルーチンが実行されるときです)。この場合、ループの現在の値は ですfoo

でレキシカル変数を使用するとmy、ループ内で使用した変数はループ外では見えず、ループの他のすべての繰り返しでも見えません。ただし、サブ自体には引き続き表示されます。これを閉鎖と呼びます。クロージャーはレキシカル変数でのみ機能し、情報隠蔽を実現したり、コード例のように特別に調整されたサブルーチンを構築したりするための強力な方法です。

于 2012-08-24T11:22:40.767 に答える
2

クロージャは、値ではなく変数をキャプチャします。

for my $xループのたびに新しい変数を作成すると考えてください。内側のサブルーチンは、値が から変化しない同様の名前のパッケージ変数の代わりに、この変数をキャプチャしますfoo

を削除するとmy、1 つの変数 (パッケージ変数) のみが作成されるため、ループ内で作成された各サブルーチンは同じ変数を参照します (その値はfooto redto to blueto ... to violettoになりますfoo)。

于 2012-08-24T11:44:57.063 に答える
1

for ループで使用される変数には、いくつかの魔法が付加されています。ループの反復ごとに、適切な値に設定されます。ループの終了後、$name は古い値に設定されます。基本的に、作成するすべてのサブは、その値を変更する同じ変数を参照します。これを示すためにあなたの例を修正しました:

@colors = qw(red blue green yellow orange purple violet);
$name = 'foo';
for $name (@colors) {
  no strict 'refs';
  *$name = sub { "<FONT COLOR='$name'></FONT>" };
  print $name . &{$name} . "\n";
}
print red() . "\n";

my次のような関数で定義することにより、ローカル変数を作成できます。

for my $name (@colors) {

経験則として、use strict;変数の初期化を強制するプログラムでは常に実行する必要があります。

于 2012-08-24T11:29:47.317 に答える