如何将参数传递给使用eval定义的Perl子例程?
问题描述:
我使用一个配置文件(YAML),以定义以后使用的类型来验证我的应用程序所需的其他配置值:如何将参数传递给使用eval定义的Perl子例程?
---
action: >
use List::MoreUtils;
my $value = $_;
any { $value eq $_ } qw(fatal keep merge non-fatal replace);
dir : return defined $_ ? -d $_ : -1;
file : return defined $_ ? -f $_ : -1;
string: 1;
---
config-element:
value: foo
type : file
etc ...
的想法是eval
每种类型的定义,将其丢入散列,然后调用验证配置数据(下面是示意性的,易于理解性):
#throw sub refs into hash
my %type_sub;
foreach my $key (keys %$type_def_ref) {
my $sub_str = "sub {$type_def_ref->{$key}}";
$type_sub{$key} = eval $sub_str;
}
#validate (myfile is a real file in the cwd)
print $type_sub{file}->('myfile'),"\n";
print $type_sub{action}->('fatal'), "\n";
的问题是,在%type_sub子程序似乎不接受参数。在上述情况下,第一个打印语句输出-1
而第二输出:
Use of uninitialized value $value in string eq at (eval 15) line 1.
Use of uninitialized value $_ in string eq at (eval 15) line 1.
Can't call method "any" without a package or object reference at
(eval 15) line 1.
这是不是在所有我所期望的,但在子程序调用。
我在做什么错?
编辑: 我正在马虎,现在一切正常。感谢弗里多。
答
您的子程序参数将在@_
数组中,而不是$_
。要获得第一个参数,请查看$_[0]
或执行my $foo = shift;
。 (shift
默认情况下@_
运行。)
至于any
,我相信这个问题是由于any
不能够在运行时加载它的原型(子程序原型只能在编译时被调用。)您可能需要使用明确的parens和明确的子程序引用:
any(sub { $value eq $_ }, qw(fatal keep merge non-fatal replace));
答
不要在配置中编写代码。用代码创建一个库,并简单地配置要使用的子程序名称。这应该可以为您节省大量的翻译字符串的代码和管理过程。当有人调整配置并引入语法错误时,它还可以节省大量的时间追踪问题。
我在Mastering Perl的“配置”一章以及动态子程序章节中对此进行了广泛的讨论。
代码不属于配置。说,直到你相信它。
哇。我一直使用@_进行移位或列表赋值,并且$ _很常见,我完全忘记了它不会自动设置。 – gvkv 2010-01-19 16:00:21
我刚刚尝试了解'任何'的解决方案,但没有运气。这里有一个更一般的问题,就是如何用eval或其他方法定义一个带有字符串的子程序。也许我会稍后再问。 – gvkv 2010-01-19 16:05:50
我修好了。 List :: MoreUtils默认不会导出任何东西。 – gvkv 2010-01-19 16:15:33