2013-05-07 6 views
11

Ich sah dieses Bit Code in einer Antwort auf einen anderen Beitrag: Why would I use Perl anonymous subroutines instead of a named one?, konnte aber nicht genau herausfinden, was los ist, also wollte ich es selbst laufen.Gemeinsame Variablen im Kontext von Unterprogrammen vs anonyme Unterprogramme

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! 

Im obigen Beispiel erhielt ich eine Warnung: „Variable a $ nicht 15. Offensichtlich in Zeile geteilt bleiben, deshalb ist der Ausgang‚unerwartet‘, aber ich verstehe immer noch nicht wirklich was passiert hier.

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 

in diesem Sinne verstehe ich nicht, was entweder in diesem Beispiel passiert. Könnte jemand bitte erklären?

Vielen Dank im Voraus.

Antwort

13

Es hat mit Compile-Time vs Laufzeitparsing von Unterprogrammen zu tun. Da die diagnostics Nachricht sagt,

Wenn die innere Unterprogramm aufgerufen wird, wird der Wert von der äußeren Unterprogramm der Variablen sehen, wie es war vor und während des ersten Aufruf der äußeren Unterprogramm; In diesem Fall, nachdem der erste Aufruf der äußeren Unterroutine abgeschlossen ist, teilen sich die innere und die äußere Unterroutine keinen gemeinsamen Wert für die Variable . Mit anderen Worten, die Variable wird nicht mehr geteilt.

mit Anmerkungen versehen Code:

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(); 

typische Ausgabe:

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

„Parsen“ ist wohl das falsche Wort hier, aber „Compilation“ scheint auch etwas falsch: IIRC, für Verschlüsse der kompilierter Code wird nur zu einer neuen Umgebung/einem neuen Bereich kombiniert, was zu einem neuen CV führt, während benannte Subs niemals zu einem neuen Bereich zurückkehren (ohne eine Neudefinition). – amon

+0

Vielen Dank, das war sehr hilfreich! –

1

Sie können \ &inner; im ersten Beispiel (nach der Definition) drucken und $ inner; in zweiter.

Was Sie sehen, sind Hex-Code Referenzen, die gleich in ersten Beispiel und unterscheiden sich in der zweiten. Also, im ersten Beispiel wird inner nur einmal erstellt, und es ist immer Schließung zu $ ​​eine lexikalische Variable aus dem ersten Aufruf der äußeren().

Verwandte Themen