2013-05-07 8 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! 

В приведенном выше примере, я получил предупреждение: «Переменная $ а не будет оставаться совместно на линии 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, для закрытия в скомпилированный код просто сочетается с новой средой/областью, в результате чего появляется новое резюме, тогда как названные субтитры никогда не восстанавливаются до новой области (без переопределения). – amon

+0

Большое спасибо, это было очень полезно! –

1

Вы можете напечатать \ &inner; в первом примере (после определения) и напечатать $ inner; во втором.

Что вы видите шестигранные код ссылки, которые равный в первом примере и различающиеся в секунду. Итак, в первом примере внутренний создается только один раз, и он всегда замыкает $ лексическую переменную от первого вызова внешнего().

Смежные вопросы