2008-10-14 8 views
24

У меня есть некоторые автоматически сгенерированный код, который эффективно выписывает следующий в куче разных мест, в каком-то коде:Как я могу локализовать переменные Perl в другом стеке стека?

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

При автоматической генерации кода, некоторые утверждают, что это не является строго необходимым, чтобы быть кодом " красиво ", но я хотел бы вытащить это в подпрограмму. Однако это локализует эти переменные в этой подпрограмме. Есть ли способ локализовать эти переменные в фрейме вызывающего стека?

Обновление: В аналогичном ключе было бы неплохо иметь возможность запускать eval в более высоком стеке стека. Я думаю, что у Python уже есть это. Было бы неплохо, если бы и Перл тоже.

+0

Вы уверены, что видели это на Python? Tcl `uplevel` приходит в голову. Но ответ Хектена намного лучше. – cfi 2012-01-11 14:20:32

ответ

30

Возможно, вы можете организовать код, в котором эти местные жители будут созданы как закрытие? Тогда вы могли бы

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 
}); 
3

Я не очень хорошо знаком с Perl, так что простите меня, если это действительно возможно. Но обычно переменные, локальные для фрейма стека, доступны только в этом стеке стека. Вы не можете получить к ним доступ ни с более высокой, ни с более низкой (если вы не выполняете арифметику хакерских указателей, но это никогда не будет гарантировано). Большие блоки переменных объявлений, к сожалению, с которыми вам придется жить.

QuantumPete

+1

Эти переменные являются встроенными глобальными переменными. У них нет обычных когнитивных издержек глобалов, поскольку они хорошо известны и определены. К сожалению, они по-прежнему имеют глобальный эффект (как это делают глобальные переменные), и локализация ограничивает изменения текущей области. – Ovid 2008-10-14 10:11:43

+2

Кроме того, у местного нет такого поведения, о котором вы думаете, а не точно. local позволяет вам получить доступ к переменной, которая локализована с этого момента, изменить ее, обновить, изменить и продолжить в этом стеке вызовов в качестве вашего нового/модифицированного значения до тех пор, пока он не будет закрыт, в котором он был локализован. – 2008-10-16 20:06:25

1

В TCL вы можете использовать uplevel. Что касается Perl, я не знаю.

+3

Мне нужно задаться вопросом почему, черт возьми, есть запись в Википедии для ключевого слова TCL?Должен ли я добавить его для распаковки сейчас? :) – Ovid 2008-10-14 12:18:07

6

Не знаете, почему QuantumPete сокращается, он, кажется, прав на этом. Вы не можете указать local для инициализации переменных в вызывающем блоке. Его функциональность является особенной, а инициализация/отрыв, который он выполняет, работает только на блоке, где он был запущен.

Есть некоторые экспериментальные модули, такие как Sub::Uplevel и Devel::RunBlock которые позволяют попытаться «обмануть» caller() для подпрограмм или сделать «длинный прыжок возвращение» значений к более высоким кадрам стеки (соответственно), но ни один из них ничего делать чтобы повлиять на то, как local обрабатывает переменные (я пробовал. :)

Так вот, действительно, похоже, вам придется жить с локальными объявлениями в области, в которой они вам нужны.

3

perldoc perlguts говорит:

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. Я не смотрел на Alias.pm достаточно близко, чтобы понять, насколько это возможно.