Das Problem ist, dass das sub name {...}
-Konstrukt nicht wie in einer for
-Schleife verschachtelt werden kann.
Der Grund ist, weil sub name {...}
wirklich BEGIN {*name = sub {...}}
bedeutet und begin-Blöcke ausgeführt werden, sobald sie analysiert werden. Also erfolgt die Kompilierung und variable Bindung der Subroutine zur Kompilierungszeit, bevor die for-Schleife überhaupt ausgeführt werden kann.
Sie möchten eine anonyme Subroutine erstellen, die ihre Variablen zur Laufzeit bindet:
%Vor%welches druckt
%Vor%Vermutlich werden diese Closures in Ihrem echten Anwendungsfall in ein Array oder Hash geladen, damit sie später wieder aufgerufen werden können.
Sie können weiterhin Bareword-Bezeichner mit Closures verwenden, aber Sie müssen noch ein wenig mehr Arbeit verrichten, um sicherzustellen, dass die Namen zum Zeitpunkt der Kompilierung sichtbar sind:
%Vor%Eric Strom's Antwort ist richtig und wahrscheinlich, was Sie sehen wollten, geht aber nicht auf die Details der Bindung ein.
Eine kurze Anmerkung zur lexikalischen Lebensdauer: Lexika werden zur Kompilierzeit erstellt und sind tatsächlich verfügbar, noch bevor ihr Gültigkeitsbereich eingegeben wurde, wie dieses Beispiel zeigt:
%Vor%Danach, wenn sie den Gültigkeitsbereich verlassen, sind sie nicht mehr verfügbar, bis sie das nächste Mal in Reichweite sind:
%Vor% In Ihrem Code ist der Abschluss zur Kompilierungszeit an das anfängliche lexikalische $i
gebunden.
Foreach Schleifen sind jedoch ein wenig seltsam; während my $i
tatsächlich lexikalisch erzeugt, verwendet die foreach-Schleife es nicht; Stattdessen aliasiert es jede der Iterationen zu einem der überschleifen-Werte und stellt es dann nach der Schleife in seinen ursprünglichen Zustand zurück. Ihre Schließung ist also die einzige Sache, die auf das ursprüngliche lexikalische $i
verweist.
Eine kleine Variation zeigt mehr Komplexität:
%Vor% Hier wird das ursprüngliche $i
zur Kompilierzeit erstellt und die Schließung bindet daran; Die erste Iteration der Schleife legt sie fest, aber die zweite Iteration der Schleife erstellt ein neues $i
, das nicht mit dem Closure verknüpft ist.