我怎样才能优雅地调用一个名字被保存在variables中的Perl子程序?
我在运行时将我要调用的子例程的名称保存在名为$ action的variables中。 然后我用它在正确的时间调用这个子部分:
&{\&{$action}}();
工作正常。 我唯一不喜欢的就是它很丑,每当我这样做的时候,我都觉得应该为下一个开发者添加评论:
# call the sub by the name of $action
任何人都知道这样做更漂亮的方式?
更新:这里的想法是为了避免每次我添加一个新的可调用子文件时必须维护一个调度表,因为我是唯一的开发人员,我不担心其他程序员遵循或不遵循“规则”。 为了我的方便牺牲了一点安全性。 相反,我的调度模块会检查$ action,以确保1)它是一个定义的子例程的名称,而不是恶意代码与eval一起运行,以及2)它不会运行任何由下划线开头的子项,通过这个命名约定标记为内部唯一的子。
有关这种方法的任何想法? 在调度表中列入白名单子程序是我永远都会忘记的事情,我的客户宁愿我在“有效”一边而不是在“它是邪恶的安全”方面犯错。 (开发应用程序的时间非常有限)
最后更新:我认为我已经决定派遣表。 虽然我很好奇,如果有人读过这个问题,曾经试图取消一个这样的问题,但是我不得不跪下这里的集体智慧。 感谢所有,许多伟大的回应。
而不是将子程序名称存储在variables中并调用它们,则更好的方法是使用子程序引用的哈希(否则称为调度表) 。
my %actions = ( foo => \&foo, bar => \&bar, baz => sub { print 'baz!' } ... );
然后你可以很容易的打电话给对方:
$actions{$action}->();
您还可以添加一些检查来确保$action
是散列中的有效键,等等。
一般来说,你应该避免符号引用(你现在在做什么),因为它们会导致各种问题。 此外,使用真正的子程序引用将strict
打开工作。
Just &$action()
,但通常从一开始就使用coderefs更好,或者使用调度器散列。 例如:
my $disp = {foo => \&some_sub, bar => \&some_other_sub }; $disp->{'foo'}->();
咦? 你可以说
$action->()
例:
sub f { return 11 } $action = 'f'; print $action->(); $ perl subfromscalar.pl 11
build筑像
'f'->() # equivalent to &f()
也工作。
我不确定我明白你的意思。 (我认为这是最近一组“我怎样才能用variables作为variables名?”的问题,但也许不是)。
在任何情况下,您都应该能够将一个完整的子程序分配给一个variables(作为参考),然后直接调用它:
# create the $action variable - a reference to the subroutine my $action = \&preach_it; # later - perhaps much later - I call it $action->(); sub preach_it { print "Can I get an amen!\n" }
最重要的是:你为什么要使用variables作为函数名称。 如果是“eval”,会发生什么? 有没有可以使用的function列表? 或者它可以是任何function? 如果列表存在 – 多久?
一般来说,处理这种情况的最好方法是使用调度表:
my %dispatch = ( 'addition' => \&some_addition_function, 'multiplication' => sub { $self->call_method( @_ ) }, );
然后只是:
$dispatch{ $your_variable }->( 'any', 'args' );
我做类似的事情。 我把它分成两行,使它更容易识别,但不是很漂亮。
my $sub = \&{$action}; $sub->();
我不知道更正确或更漂亮的做法。 对于什么是价值,我们有生产代码,做你正在做什么,它的工作,而不必禁用use strict
。
__PACKAGE__->can($action)->(@args);
有关can()的更多信息: http : //perldoc.perl.org/UNIVERSAL.html
要么用
&{\&{$action}}();
或者使用eval来执行该function:
eval("$action()");
Perl中的每个包都已经是一个哈希表。 您可以添加元素并通过正常的散列操作来引用它们。 一般来说,没有必要通过附加的散列表来复制function。
#! /usr/bin/perl -T use strict; use warnings; my $tag = 'HTML'; *::->{$tag} = sub { print '<html>', @_, '</html>', "\n" }; HTML("body1"); *::->{$tag}("body2");
代码打印:
<HTML> body1 </ HTML> <HTML> body2 </ HTML>
如果你需要一个单独的名字空间,你可以定义一个专门的包。
有关更多信息,请参阅perlmod 。
我是这样做的:
@func = qw(cpu mem net disk); foreach my $item (@func){ $ret .= &$item(1); }
如果只是在一个程序中,写一个函数调用一个variables名称的子程序,只需要logging它/道歉一次?
我用这个:它适用于我。
(\$action)->();
或者你可以使用'do',与以前的post非常相似:
$p = do { \&$conn;}; $p->();