24

我有一些自动生成的代码,它们在一些代码的不同位置有效地写出以下内容:

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

在自动生成代码时,一些人认为代码“漂亮”并不是绝对必要的,但我想把它拉到一个子程序中。但是,这会将这些变量本地化在该子例程中。有没有办法在调用堆栈帧中本地化这些变量?

更新:以类似的方式,能够在更高的堆栈帧中运行 eval 会很好。我认为 Python 已经有了这个。如果 Perl 也这样做,那就太好了。

4

6 回答 6

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
});
于 2008-10-14T13:53:25.023 回答
6

不知道为什么 QuantumPete 被否决,他似乎是对的。您无法告诉local在调用块中初始化变量。它的功能很特殊,它所做的初始化/拆卸只适用于它运行的块。

有一些实验性模块,例如Sub::UplevelDevel::RunBlock,它们允许您尝试“愚弄”caller()子例程或将值“长跳转返回”到更高的堆栈帧(分别),但这些都没有任何影响如何local对待变量的东西(我试过了。:)

因此,就目前而言,确实看起来您将不得不在需要它们的范围内使用本地声明。

于 2008-10-14T12:28:40.437 回答
3

我对 Perl 不是很熟悉,所以如果真的可能,请原谅我。但通常,堆栈帧的局部变量仅在该堆栈帧内可用。您不能从更高或更低的访问它们(除非您执行一些 hacky 指针算术,但这永远不能保证成功)。不幸的是,大块的变量声明是你必须忍受的。

量子皮特

于 2008-10-14T10:05:35.310 回答
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,以了解这可能是多么容易。

于 2008-10-15T01:53:47.987 回答
1

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

于 2008-10-14T11:35:21.137 回答
0

Perl 有Sub::Uplevel

于 2008-10-17T22:08:19.577 回答