如何将参数传递给使用 eval 定义的 Perl 子例程?
我使用配置文件(在 YAML 中)来定义稍后用于验证我的应用程序所需的其他配置值的类型:
---
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 中的子例程似乎不接受参数。在上面的情况下,第一个 print 语句输出 -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.
这根本不是我所期望的,但子例程正在被调用。
我做错了什么?
编辑: 我当时很马虎,现在一切都很好。感谢弗里多。
I'm using a config file (in YAML) to define types that are used later on to validate other config values required for my app:
---
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 ...
The idea is to eval
each type definition, throw them into a hash and then call to validate configuration data (the following is schematic for easy comprehensibility):
#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";
The problem is that the subroutines in %type_sub don't seem to accept parameters. In the above case, the first print statement outputs -1
while the second outputs:
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.
which is not at all what I expect, yet the subroutines are being called.
What am I doing wrong?
EDIT:
I was being sloppy and everything works fine now. Thanks to Friedo.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不要在配置中编写代码。使用代码创建一个库,然后简单地配置您要使用的子例程名称。这将为您节省大量将字符串转换为代码和管理流程的工作。当有人调整配置并引入语法错误时,它还可以为您节省大量跟踪问题的时间。
我在 掌握 Perl 的“配置”章节以及有关动态的章节中广泛讨论了这一点子程序。
代码不属于配置。这么说直到你相信为止。
Don't write code in configuration. Create a library with the code and simply configure which subroutine name you want to use. That should save you an huge amount of work translating strings to code and managing the process. It also saves you a ton of time tracking down problems when someone adjusts the configuration and introduces a syntax error.
I talk about this extensively in the "Configuration" chapter in Mastering Perl, as well as the chapters on dynamic subroutines.
Code doesn't belong in configuration. Say that until you believe it.
您的子例程参数将位于
@_
数组中,而不是$_
中。要获取第一个参数,请查看$_[0]
或执行my $foo = shift;
。 (shift
默认在@_
上运行。)至于
any
,我相信问题是由于any
造成的无法在运行时加载其原型(子例程原型只能在编译时调用。)您可能需要使用显式括号和显式子例程引用:Your subroutine parameters will be in the
@_
array, not$_
. To get the first parameter, look in$_[0]
or domy $foo = shift;
. (shift
operates on@_
by default.)As for
any
, I believe the problem is due toany
not being able to load its prototype at runtime (subroutine prototypes can only be called at compile-time.) You may need to use explicit parens and an explicit subroutine reference: