我需要在另一个包中本地化一些变量,但是在传入之前我不知道它们的名字是什么。我尝试将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" }
我试图避免像这样的评估:
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
下工作。当前的解决方案是有效的,所以我不是在寻找黑客来解决我正在做的事情,我正在寻找更好的解决方案(如果存在的话)。
答案 0 :(得分: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();
我愿意接受更好的想法。