Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何优雅地调用名保存在变量中的Perl子例程?_Perl - Fatal编程技术网

如何优雅地调用名保存在变量中的Perl子例程?

如何优雅地调用名保存在变量中的Perl子例程?,perl,Perl,我将要在运行时调用的子例程的名称保存在名为$action的变量中。然后我用这个在正确的时间调用sub: &{\&{$action}}(); 很好。我唯一不喜欢的是它很难看,每次我这么做时,我都觉得有必要为下一个开发者添加一条评论: # call the sub by the name of $action 有人知道更漂亮的方法吗 更新:这里的想法是避免每次我添加新的可调用sub时都必须维护调度表,因为我是唯一的开发人员,我不担心其他程序员遵守或不遵守“规则”。为了我的方便牺

我将要在运行时调用的子例程的名称保存在名为$action的变量中。然后我用这个在正确的时间调用sub:

&{\&{$action}}();
很好。我唯一不喜欢的是它很难看,每次我这么做时,我都觉得有必要为下一个开发者添加一条评论:

# call the sub by the name of $action
有人知道更漂亮的方法吗


更新:这里的想法是避免每次我添加新的可调用sub时都必须维护调度表,因为我是唯一的开发人员,我不担心其他程序员遵守或不遵守“规则”。为了我的方便牺牲了一点安全。相反,我的调度模块将检查$action,以确保1)它是定义的子例程的名称,而不是使用eval运行的恶意代码,2)它不会运行任何以下划线开头的子例程,下划线将根据此命名约定标记为仅内部子例程

对这种方法有什么想法吗?在分派表中白名单子例程是我一直都会忘记的事情,我的客户宁愿我犯“它工作”而不是“它非常安全”的错误。(开发应用程序的时间非常有限)



最后更新:我想我已经决定了一个调度表。尽管我很好奇,如果有人读到这个问题,有没有人试图废除一个,以及他们是如何做到的,但我不得不向这里的集体智慧低头。感谢大家,有很多很棒的回答。

如果它只在一个程序中,那么编写一个使用变量名调用子例程的函数,并且只需记录它/道歉一次?

我不确定我是否理解你的意思。(我认为这是最近一组“如何使用变量作为变量名?”问题中的另一个问题,但可能不是。)

在任何情况下,您都应该能够将整个子例程分配给变量(作为引用),然后直接调用它:

# 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"
}
只需
和$action()
,但通常最好从一开始就使用coderefs,或者使用dispatcher散列。例如:

my $disp = {foo => \&some_sub, bar => \&some_other_sub };
$disp->{'foo'}->();

我也做类似的事情。我把它分为两行,让它更容易识别,但也不是更漂亮

my $sub = \&{$action};
$sub->();

我不知道有哪种方法更正确或更漂亮。值得一提的是,我们的生产代码可以执行您正在执行的操作,并且无需禁用
使用strict

即可工作,而不是将子例程名称存储在变量中并调用它们,更好的方法是使用子例程引用的散列(也称为a)

然后你可以很容易地找到合适的人:

$actions{$action}->();
您还可以添加一些检查,以确保
$action
是散列中的有效键,依此类推


一般来说,您应该避免符号引用(您现在正在做的事情),因为它们会导致各种问题。此外,使用实子程序引用将在启用
strict
的情况下工作。

最重要的是:为什么要使用变量作为函数名。如果是“评估”,会发生什么? 是否有可以使用的功能列表?或者它可以是任何功能?如果列表存在-它有多长

通常,处理此类情况的最佳方法是使用调度表:

my %dispatch = (
   'addition' => \&some_addition_function,
   'multiplication' => sub { $self->call_method( @_ ) },
);
然后就是:

$dispatch{ $your_variable }->( 'any', 'args' );
嗯?你可以说

    $action->()
例如:

    sub f { return 11 }
    $action = 'f';
    print $action->();


    $ perl subfromscalar.pl
    11
结构如

    'f'->()     # equivalent to   &f()
同样有效。

使用

&{\&{$action}}();
或使用eval执行该功能:

eval("$action()");
我是这样做的:

@func = qw(cpu mem net disk);
foreach my $item (@func){
    $ret .= &$item(1);
}

我用过这个:它对我有用

(\$action)->();
或者你也可以使用“do”,与之前的帖子非常相似:

$p = do { \&$conn;}; 
$p->();

Perl中的每个包都已经是一个哈希表。您可以添加元素并通过常规哈希操作引用它们。通常,不需要通过附加的哈希表来复制功能

#! /usr/bin/perl -T
use strict;
use warnings;

my $tag = 'HTML';

*::->{$tag} = sub { print '<html>', @_, '</html>', "\n" };

HTML("body1");

*::->{$tag}("body2");
#/usr/bin/perl-T
严格使用;
使用警告;
我的$tag='HTML';
*:::->{$tag}=sub{print'',@_'',“\n};
HTML(“body1”);
*::->{$tag}(“body2”);
代码打印:

<html>body1</html> <html>body2</html> 车身1 车身2 如果需要单独的名称空间,可以定义专用包

有关更多信息,请参阅

__PACKAGE__->can($action)->(@args);

有关can()的更多信息:

使用我得到的&$action解决方案:在“strict refs”时不能将字符串(“main::instructors”)用作子例程ref。那么,我所做的体操仅仅是因为我打开了“严格”功能吗?是的,这种用法是“严格使用”所阻止的(除其他外)。使用“无严格的“引用”来允许它,但同样,实际引用或分派器通常更清晰。分派表答案使用真实(而不是符号)引用,当然可以在启用
strict
的情况下工作,这是这样做的另一个优点。
使用严格的qw(vars subs)
是表示
严格使用的较短方式;没有严格的“参考文献”
@mobrule:除非有人添加第四类限制,即:)意识到当你引用某个东西以立即取消引用它时,你可以跳过中间的步骤。:)@布莱恩:通常(在这种情况下是肯定的),但请看一个反例:分派表还意味着您可以
使用strict
,这通常是一件好事。如果
使用strict
(当然,您会这么做),您需要说
没有严格的“refs”
,或者只
使用strict qw(vars subs)
来使用此语法。如果它对任何人都有帮助,如果您还想将参数传递给子例程,您只需将它们放在()之间,即与普通sub相同。例如,
$sub->($parmVariable,11,'a')
从子系统中反射性地调用此函数;my$this=\&{(调用者(0))[3]}$return=$this->()$return.=$this->(\@flags,\%arguments,\%foo);我在下面的另一个答案中重复了我的评论,因为这个答案是迄今为止得分最高的!如果它对任何人都有帮助,如果您还想将参数传递给子例程,只需将它们放在()之间,即与普通子例程相同。例如,
$actions{$action}->($parmVariable,11,'a')__PACKAGE__->can($action)->(@args);