2008-10-14 7 views
24

Ich habe einige automatisch generierten Code, der aus den folgenden in einer Reihe von verschiedenen Orten in einigen Code effektiv schreibt:Wie kann ich Perl-Variablen in einem anderen Stapelrahmen lokalisieren?

no warnings 'uninitialized'; 
local %ENV = %ENV; 
local $/ = $/; 
local @INC = @INC; 
local %INC = %INC; 
local $_ = $_; 
local $| = $|; 
local %SIG = %SIG; 
use warnings 'uninitialized'; 

Wenn Auto-Code generieren, einige argumentieren, dass es der Code "nicht unbedingt notwendig ist, dass schön ", aber ich möchte das in eine Unterroutine herausziehen. Dies würde jedoch die Variablen in dieser Subroutine lokalisieren. Gibt es eine Möglichkeit, diese Variablen im aufrufenden Stack-Frame zu lokalisieren?

Update: In ähnlicher Weise wäre es schön, Eval in einem höheren Stack-Frame ausführen zu können. Ich denke, Python hat das schon. Es wäre schön, wenn auch Perl es wäre.

+0

Sind Sie sicher, dass Sie das in Python gesehen haben? Tcl's 'Uplevel' kommt mir in den Sinn. Aber Hextens Antwort ist sowieso viel besser. – cfi

Antwort

30

Vielleicht können Sie veranlassen, dass der Code, der diese Locals verwendet, als Closure generiert wird? Dann könnten Sie

sub run_with_env { 
    my ($sub, @args) = @_; 
    no warnings 'uninitialized'; 
    local %ENV = %ENV; 
    local $/ = $/; 
    local @INC = @INC; 
    local %INC = %INC; 
    local $_ = $_; 
    local $| = $|; 
    local %SIG = %SIG; 
    use warnings 'uninitialized'; 
    $sub->(@args); 
} 

run_with_env(sub { 
    # do stuff here 
}); 

run_with_env(sub { 
    # do different stuff here 
}); 
+2

D'oh! Das ist peinlich offensichtlich im Nachhinein :) Da ich Code automatisch generiere, ist das trivial. – Ovid

+0

Das ist eine nette Idee, das Problem so umzukehren! –

+0

Es klingt, als ob Sie% main :: wirklich lokalisieren möchten. Ich frage mich, ob es einen Weg gibt, das zu tun. –

3

Ich bin nicht sehr vertraut mit Perl, also vergib mir, wenn es tatsächlich möglich ist. Normalerweise sind Variablen, die für einen Stapelrahmen lokal sind, nur innerhalb dieses Stapelrahmens verfügbar. Sie können auf sie weder von einem höheren noch von einem niedrigeren zugreifen (es sei denn, Sie führen eine Hacker-Pointer-Arithmetik durch, aber das ist niemals garantiert). Große Blöcke variabler Deklarationen sind leider etwas, womit Sie leben müssen.

QuantumPete

+1

Diese Variablen sind eingebaute globale Variablen. Sie haben nicht den üblichen kognitiven Overhead von Globalen, wie sie allgemein bekannt und definiert sind. Leider haben sie immer noch globale Auswirkungen (wie globale Variablen) und die Lokalisierung beschränkt Änderungen auf den aktuellen Bereich. – Ovid

+2

Außerdem hat lokal nicht das Verhalten, an das Sie denken, nicht genau. Mit local können Sie auf die Variable zugreifen, die von da an lokalisiert ist, sie ändern, aktualisieren, ändern und in diesem Aufrufstapel als neuen/geänderten Wert fortfahren lassen, bis sie den Abschluss, in dem sie lokalisiert wurde, verlässt. –

1

In TCL können Sie uplevel verwenden. Was Perl angeht, ich weiß es nicht.

+3

Ich muss mich fragen Warum zur Hölle gibt es einen Wikipedia-Eintrag für ein TCL-Schlüsselwort?Soll ich jetzt einen zum Auspacken hinzufügen? :) – Ovid

+0

Etwas wie [Sub :: Uplevel] (http://search.cpan.org/perldoc?Sub::Uplevel)? Ist es das, wofür es ist? – bart

+0

Ich glaube nicht, Sub :: Uplevel hilft überhaupt, ich habe Angst - "Caller" ist kein Namespace. –

6

Nicht sicher, warum QuantumPete downvoted ist, scheint er auf diesem eine Recht zu haben. Sie können local nicht anweisen, Variablen im aufrufenden Block zu initialisieren. Seine Funktionalität ist speziell, und die Initialisierung/Teardown funktioniert nur in dem Block, in dem sie ausgeführt wurde.

Es gibt einige experimentelle Module wie Sub::Uplevel und Devel::RunBlock, die Sie für Subroutinen „zu täuschen“ caller() erlauben, zu versuchen, oder eine ‚Weitsprung Rückkehr‘ von Werten zu höheren Stapelrahmen (jeweils) tun, aber keiner von ihnen etwas zu tun zu beeinflussen, wie local Variablen behandelt (Ich versuchte. :)

So für jetzt sieht es wirklich so aus, als müssten Sie mit den lokalen Deklarationen in dem Bereich leben, in dem Sie sie benötigen.

3

Perldoc perlguts sagt:

The "Alias" module implements localization of the basic types within 
    the caller's scope. People who are interested in how to localize 
    things in the containing scope should take a look there too. 

FWIW. Ich habe Alias.pm nicht genau genug angeschaut, um zu sehen, wie einfach das sein könnte.