23

ここでも Perl の初心者で、Perl で理解しようとしていclosureます。

だからここに私が理解していないコードの例があります:

sub make_saying  {
    my $salute = shift;
    my $newfunc = sub {
        my $target = shift;
        print "$salute, $target!\n";
    };
    return $newfunc;            # Return a closure
}
$f = make_saying("Howdy");      # Create a closure
$g = make_saying("Greetings");  # Create another closure
# Time passes...
$f->("world");
$g->("earthlings");

だから私の質問は:

  1. 変数が関数に割り当てられている場合、それは自動的にその関数への参照になりますか?
  2. 上記のコードでは、$f = \make_saying("Howdy")代わりに書くことができますか? そして&、パラメータ(&$f("world"))を渡すときにそれを使用しようとしたため、いつ使用できますが、機能しません。
  3. そして最後に、上記のコードでは、彼**が単語worldを実行earthlingsし、単語に追加され、単語に追加されましhowdygreetings

注: $f はパラメーターを使用して関数にある程度バインドされていることを理解しているため、追加されたhowdy方法を理解しています。world私が理解していないのは、内部の2番目の機能です。あれがどのようにその魔法を操作するか。申し訳ありませんが、この質問の仕方がわかりません。

4

3 に答える 3

16

Perl では、スカラー変数はサブルーチンを直接保持できず、参照のみを保持できます。これは、スカラーが配列またはハッシュを保持できず、配列参照またはハッシュ参照のみを保持するのと非常によく似ています。

sub { ... }coderef に評価されるため、スカラー変数に直接割り当てることができます。名前付き関数 (例: ) を割り当てたい場合はfoo、 のような参照を取得する必要があります\&foo

$code->(@args)またはのような coderefs を呼び出すことができます&$code(@args)

コード

$f = \make_saying("Howdy")

を評価make_saying("Howdy")し、戻り値への参照を取ります。したがって、コードリファレンス自体ではなく、コードリファレンスを指す参照を取得します。

したがって、 のように呼び出すことはできません&$f("world")。1 つの余分なレベルを逆参照する必要があります: &$$f("world")


クロージャは、特定の環境にバインドされた関数です。

環境は現在表示されているすべての変数で構成されているため、クロージャーは常にこのスコープを記憶しています。コード内

my $x;
sub foo {
  my $y;
  return sub { "$x, $y" };
}

foo$x外部環境は で構成されているため、は のクロージャーです$x。内側のサブは$xandのクロージャ$yです。

fooが実行されるたびに、新しいもの$y、つまり新しいクロージャが取得されます。呼び出されるたびに、異なるクロージャが返されます。

を実行するmake_saying("Howdy")と、$salute変数は に設定されHowdyます。返されたクロージャーは、このスコープを記憶しています。

で再度実行するとmake_saying("Greetings")、 の本体がmake_saying再度評価されます。がに$salute設定されGreetings、内部サブがこの変数を閉じます。この変数は以前の とは別のもので、$saluteまだ存在していますが、最初のクロージャー以外ではアクセスできません。

2 つのグリーターは、別々の$salute変数で閉じています。それらが実行されると、それぞれ$saluteはまだスコープ内にあり、値にアクセスして変更できます。

于 2013-06-11T08:34:09.790 に答える
4

変数が関数に割り当てられている場合、それは自動的にその関数への参照になりますか?

いいえ。例では、関数make_sayingreturnは別の関数を参照しています。このようなクロージャーには名前がなく、そのスコープ外から変数をキャッチでき$saluteます(例の変数)。

上記のコードでは、代わりに $f = \make_saying("Howdy") と記述できますか? & を使用できるのはいつですか?パラメーター (&$f("world")) を渡す際にそれを使用しようとしましたが、機能しません。

いいえ$f = \make_saying("Howdy")、あなたの考えではありません (詳細についてはamonの投稿をお読みください)。$f = \&make_saying;「関数make_sayingへの参照を$fに入れる」という意味を書くことができます。後で次のように使用できます。

my $f = \&make_saying;
my $other_f = $f->("Howdy");
$other_f->("world");

そして最後に、上記のコードでは、どのように he** という言葉が世界で使用され、地球人がハウディと挨拶という言葉に追加されました。

ラムダに入る私の変数を作成するmake_sayingmy $newfunc = sub ( ); そのラムダはmake_sayingから返されます。指定された単語「Howdy」を「closeing」で保持します (? 申し訳ありませんが、英語でどの単語かわかりません)。

于 2013-06-11T08:29:55.743 に答える
0

サブルーチン「make_saying」を呼び出すたびに、次のようになります。

  1. DIFFERENT クロージャを作成します

  2. 受け取ったパラメーターをスカラー '$salute' に割り当てます

  3. $target内部の無名サブルーチンを定義 (作成しますが、実行はしません): これが、その時点でスカラーに何も割り当てられず、ステートメントがprint "$salute, $target!\n";実行されない理由 です。

  4. 最後に、サブルーチン 'make_saying' は内部の無名サブルーチンへの参照を返します。その参照が (特定の) 無名サブルーチンを呼び出す唯一の方法になります。

各匿名サブルーチンを呼び出すたびに、次のようになります。

  1. 受け取ったパラメーターをスカラーに代入します$target

  2. $saluteまた、無名サブルーチンが作成された時点 (親サブルーチンが呼び出されたとき) に割り当てられた値を持つスカラーも表示されます。make_saying

  3. 最後にステートメントを実行しますprint "$salute, $target!\n";

于 2014-10-23T13:45:31.247 に答える