2009-04-27 24 views
2

我需要本地化一些變量到另一個包中,但我不知道他們的名字是什麼,直到他們通過。我嘗試使用local與typeglobs沒有工作,所以我已退回到保存價值該變量並手動恢復它。有沒有更好的辦法?請注意,錯誤檢查以查看變量是否存在之前已被清除。當我只在運行時知道他們的名字時,如何本地化另一個包中的變量?

#!/usr/bin/perl 

use strict; 
use warnings; 

my %orig; 
for my $name (qw/foo bar baz/) { 
    my $var = \${$meta::{$name}}; 
    $orig{$name} = $$var; 
    $$var = $$var * 2; 
} 
meta::p(); 
for my $name (keys %orig) { 
    my $var = \${$meta::{$name}}; 
    $$var = $orig{$name}; 
} 
meta::p(); 

package meta; 

BEGIN { 
    our $foo = 1; 
    our $bar = 2; 
    our $baz = 3; 
} 

sub p { print join(" :: ", $meta::foo, $meta::bar, $meta::baz), "\n" } 

我試圖避免這樣一個eval:

my $eval = ''; 

for my $name (qw/foo bar baz/) { 
    $eval .= "local \$meta::$name = \$meta::$name * 2;\n"; 
} 

eval "$eval meta::p()"; 
meta::p(); 

試圖避免的EVAL浪費時間嗎?新代碼比eval更糟糕嗎?

請注意,我也不想使用符號引用,所有代碼必須在strict下工作。目前的解決方案的工作原理,所以我不尋找黑客來解決我在做什麼,我正在尋找更好的解決方案(如果存在的話)。

回答

3

關閉strict refs應該允許你用symbolic references做你想做的。我沒有對系統的訪問做ATM測試,但這樣的事情應該工作:

use strict; 
use warnings; 

{ 
    no strict `refs`; 
    local ${"meta::$name"} = ${"meta::$name"} * 2; 

    meta::p(); 
} 

meta::p(); 

更新:

一些測試後,我發現了一個障礙。

雖然很容易在單個符號引用上使用local。但是爲了本地化一個變量名稱數組並不那麼簡單 - 循環結構(map,for等)都會在它們操作的表達式上創建一個小的範圍,這會終止本地化。

# This works but does not work on an array of names. 
{ no strict 'refs'; 

    local (${'meta::foo'}, ${'meta::bar'}, ${'meta::baz'}); 
    meta::p(); 
} 
meta::p(); 


# THIS DOES NOT WORK AT ALL! 
{ no strict 'refs'; 

    my @to_localize = map "meta::$_", qw/foo bar baz/; 

    local ${$_} = $$_ * 2 for @to_localize; 
    meta::p(); 

} 
meta::p(); 

我所能找到的唯一解決方案使用goto,這大家都知道是認爲是有害的

{ no strict 'refs'; 

    my @to_localize = map "meta::$_", qw/foo bar baz/; 

    LOCALIZER: 
     my $localize_me = shift @to_localize; 
     local ${$localize_me} = $$localize_me * 2; 
     goto LOCALIZER if @to_localize; 

    meta::p(); 

} 
meta::p(); 

我接受更好的想法。

+0

我應該放在那裏,我不想使用符號引用。 – 2009-04-27 15:49:41

相關問題