2008-10-14 39 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已经有了。如果Perl也这样做,那将会很好。

+0

您确定您在Python中看到了这个吗?记得Tcl的'uplevel'。但是,无论如何,hexten的答案要好得多。 – 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

另外,本地没有你想到的行为,不完全是。本地允许你访问变量,然后对其进行本地化,修改,更新,更改,然后让它继续作为新的/修改的值,直到它离开它本地化的闭包。 – 2008-10-16 20:06:25

1

在TCL,您可以使用uplevel。至于Perl,我不知道。

+3

我不得不疑惑为什么地狱有一个TCL关键词的维基百科条目?我现在应该添加一个解包吗? :) – Ovid 2008-10-14 12:18:07

6

不知道为什么QuantumPete被低估,他似乎是正确的这一个。你不能告诉local初始化调用块中的变量。它的功能是特殊的,它的初始化/拆卸只在它运行的块上有效。

有一些实验模块,如Sub::UplevelDevel::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,看看这可能是多么容易。