2009-04-27 58 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

相关问题