2013-05-07 6 views
11

別の投稿への回答でこのコードを見ました:Why would I use Perl anonymous subroutines instead of a named one?しかし、何が起こっているかを正確に把握できなかったので、私はそれを自分で実行したいと思いました。上記の例ではサブルーチンと匿名サブルーチンのコンテキストでの共有変数

sub outer 
{ 
    my $a = 123; 

    sub inner 
    { 
    print $a, "\n"; #line 15 (for your reference, all other comments are the OP's) 
    } 

    # At this point, $a is 123, so this call should always print 123, right? 
    inner(); 

    $a = 456; 
} 

outer(); # prints 123 
outer(); # prints 456! Surprise! 

、私は警告を受けた:予期しない、「変数$ aがライン明らかに15 で共有滞在しないだろう、出力されている理由です 『』私はまだ本当に理解していませんここで何が起こっている。同じ静脈で

sub outer2 
{ 
    my $a = 123; 

    my $inner = sub 
    { 
    print $a, "\n"; 
    }; 

    # At this point, $a is 123, and since the anonymous subrotine 
    # whose reference is stored in $inner closes over $a in the 
    # "expected" way... 
    $inner->(); 

    $a = 456; 
} 

# ...we see the "expected" results 
outer2(); # prints 123 
outer2(); # prints 123 

、私はどちらか、この例では何が起こっているか理解していない。誰かが説明していただけますか?事前に

感謝を。

答えて

13

サブルーチンのコンパイル時と実行時の解析とが関係します。 diagnosticsメッセージが言うように、内側のサブルーチンが呼び出されると、それは外側のサブルーチンへ最初 呼び出し前との間にあったように、

は、それが 外側のサブルーチンの変数の値が表示されます。この場合、外部サブルーチン への最初の呼び出しが完了した後、内部サブルーチンと外部サブルーチンは、変数の共通の値をより長く共有することはありません( )。つまり、変数 は共有されなくなります。

sub outer 
{ 
    # 'my' will reallocate memory for the scalar variable $a 
    # every time the 'outer' function is called. That is, the address of 
    # '$a' will be different in the second call to 'outer' than the first call. 

    my $a = 123; 


    # the construction 'sub NAME BLOCK' defines a subroutine once, 
    # at compile-time. 

    sub inner1 
    { 

    # since this subroutine is only getting compiled once, the '$a' below 
    # refers to the '$a' that is allocated the first time 'outer' is called 

    print "inner1: ",$a, "\t", \$a, "\n"; 
    } 

    # the construction sub BLOCK defines an anonymous subroutine, at run time 
    # '$inner2' is redefined in every call to 'outer' 

    my $inner2 = sub { 

    # this '$a' now refers to '$a' from the current call to outer 

    print "inner2: ", $a, "\t", \$a, "\n"; 
    }; 

    # At this point, $a is 123, so this call should always print 123, right? 
    inner1(); 
    $inner2->(); 

    # if this is the first call to 'outer', the definition of 'inner1' still 
    # holds a reference to this instance of the variable '$a', and this 
    # variable's memory will not be freed when the subroutine ends. 

    $a = 456; 
} 
outer(); 
outer(); 

典型的な出力:あなたのコードを注釈

inner1: 123  SCALAR(0x80071f50) 
inner2: 123  SCALAR(0x80071f50) 
inner1: 456  SCALAR(0x80071f50) 
inner2: 123  SCALAR(0x8002bcc8) 
+1

「構文解析」は、おそらくここで間違った言葉ですが、「コンパイル」あまりにも少し間違っているようだ:IIRC、閉鎖のためにコンパイルされたコードは単に新しい環境/スコープに結合され、結果として新しいCVが生成されますが、名前の付いたサブシステムは決して新しいスコープに再定義されません(再定義なし)。 – amon

+0

ありがとう、とても助かりました! –

1

最初の例(定義後)に\ &inner;を印刷し、$ innerを出力できます。秒です。

最初の例ではと等しいであり、2番目の例では16進コードの参照があります。 したがって、最初の例では、innerは一度だけ作成され、outer()の最初の呼び出しからの語彙変数$には常に閉じます。

関連する問題