2008-10-14 78 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,看看這可能是多麼容易。