繁体   English   中英

我怎样才能优雅地调用名称保存在变量中的Perl子例程?

[英]How can I elegantly call a Perl subroutine whose name is held in a variable?

我保留了我想在运行时在名为$ action的变量中调用的子例程的名称。 然后我用它在正确的时间调用该子:

&{\&{$action}}();

工作良好。 我唯一不喜欢的是它很丑陋,每次我这样做,我都感到很高兴为下一个开发者添加评论:

# call the sub by the name of $action

有人知道更漂亮的方式吗?


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

有关这种方法的任何想法? 发送表中的白名单子程序是我一直都会忘记的东西,我的客户宁愿我在“它工作”而不是“它是邪恶的安全”方面犯错误。 (开发应用程序的时间非常有限)


最后更新:我想我毕竟已经决定了一个调度表。 虽然我很好奇,如果读过这个问题的人曾经试图废除一个以及他们是如何做到的,那么我不得不向这里的集体智慧屈服。 感谢所有,许多伟大的回应。

不是将子例程名称存储在变量中并调用它们,更好的方法是使用子例程引用的哈希(也称为分派表)

my %actions = ( foo => \&foo,
                bar => \&bar,
                baz => sub { print 'baz!' } 
                ... 
              );

然后你可以轻松地拨打正确的电话:

$actions{$action}->();

您还可以添加一些检查以确保$action是哈希中的有效键,依此类推。

一般来说,你应该避免使用符号引用(你现在正在做什么),因为它们会导致各种各样的问题。 此外,使用实际子例程引用将strict打开。

只是&$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

像。这样的结构

    'f'->()     # equivalent to   &f()

也工作。

我不确定我明白你的意思。 (我认为这是最近一组“如何使用变量作为变量名?”的问题,但可能没有。)

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

# 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"
}

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

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

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

然后就是:

$dispatch{ $your_variable }->( 'any', 'args' );
__PACKAGE__->can($action)->(@args);

有关can()的更多信息: http//perldoc.perl.org/UNIVERSAL.html

我做了类似的事情。 我把它分成两行,使它更容易识别,但它并不是很漂亮。

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

我不知道更正确或更漂亮的方式。 对于它的价值,我们有生产代码可以完成您正在做的事情,并且无需禁用use strict

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

#! /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

要么使用

&{\&{$action}}();

或者使用eval执行该功能:

eval("$action()");

我是这样做的:

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

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

我用过这个:它对我有用。

(\$action)->();

或者您可以使用'do',与以前的帖子非常相似:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM