2008-10-14 4 views
24

J'ai un code généré automatiquement qui écrit efficacement ce qui suit dans un tas d'endroits différents dans un code:Comment localiser les variables Perl dans un cadre de pile différent?

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

Lorsque le code de génération automatique, certains affirment que ce n'est pas strictement nécessaire que le code soit " belle ", mais je voudrais tirer cela dans un sous-programme. Cependant, cela localiserait ces variables dans ce sous-programme. Y at-il un moyen de localiser ces variables dans le cadre de la pile d'appel?

Mise à jour: Dans la même veine, il serait agréable d'être en mesure d'exécuter eval dans un cadre de pile supérieure. Je pense que Python a déjà ça. Ce serait bien si Perl aussi.

+0

Etes-vous sûr que vous avez vu cela en Python? Le 'uplevel' de Tcl vient à l'esprit. Mais la réponse d'hexten est bien meilleure quand même. – cfi

Répondre

30

Peut-être que vous pouvez faire en sorte que le code qui utilise ces sections locales soit généré en tant que fermeture? Ensuite, vous pouvez

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! C'est rétrospectivement embarrassant évident :) Comme je suis auto-générateur de code, c'est trivial. – Ovid

+0

C'est une idée géniale, inversant le problème comme ça! –

+0

On dirait que vous voulez vraiment localiser% main ::. Je me demande s'il existe un moyen de le faire. –

3

Je ne suis pas très familier avec Perl, alors pardonnez-moi si c'est réellement possible. Mais normalement, les variables locales à un cadre de pile ne sont disponibles que dans ce cadre de pile. Vous ne pouvez pas y accéder à partir d'une valeur supérieure ou inférieure (sauf si vous faites de l'arithmétique avec un pointeur hacky mais que cela ne garantit jamais le succès). De grands blocs de déclarations variables sont malheureusement quelque chose que vous devrez vivre avec.

QuantumPete

+1

Ces variables sont des variables globales intégrées. Ils n'ont pas les frais cognitifs habituels des globals car ils sont bien connus et définis. Malheureusement, ils ont toujours un effet global (comme le font les variables globales) et la localisation limite les changements à la portée actuelle. – Ovid

+2

En outre, local n'a pas le comportement que vous envisagez, pas exactement. local vous permet d'accéder à la variable localisée depuis, de la modifier, de la mettre à jour, de la modifier et de la laisser continuer dans cette pile en tant que nouvelle valeur/modifiée jusqu'à ce qu'elle soit fermée. –

1

TCL vous pouvez utiliser uplevel. Quant à Perl, je ne sais pas.

+3

Je me demande pourquoi diable il y a une entrée Wikipedia pour un mot clé TCL?Dois-je en ajouter un pour déballer maintenant? :) – Ovid

+0

Quelque chose comme [Sub :: Uplevel] (http://search.cpan.org/perldoc?Sub::Unevel)? Est-ce que c'est pour ça? – bart

+0

Je ne pense pas que Sub :: Uplevel aide du tout j'ai peur - "appelant" n'est pas un espace de noms. –

6

Je ne sais pas pourquoi QuantumPete est downvoted, il semble avoir raison sur celui-ci. Vous ne pouvez pas indiquer local pour initialiser les variables dans le bloc appelant. Sa fonctionnalité est spéciale, et l'initialisation/démontage qu'il fait ne fonctionne que sur le bloc où il a été exécuté.

Il y a quelques modules expérimentaux tels que Sub::Uplevel et Devel::RunBlock qui vous permettent de tenter de « tromper » caller() pour les sous-routines ou faire un « long retour de saut » de valeurs à des cadres de pile supérieur (respectivement), mais aucun de ces rien faire pour affecter la façon dont local traite les variables (j'ai essayé. :)

Pour l'instant, il semblerait bien que vous deviez vivre avec les déclarations locales dans la portée où vous en avez besoin.

3

Perldoc perlguts dit:

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. Je n'ai pas regardé Alias.pm assez près pour voir comment cela pourrait être facile.

Questions connexes