如何使用变量名调用perl中的子例程

时间:2017-01-05 09:48:37

标签: perl call subroutine

假设我有一个包含所有子程序名称的数组,我想逐个调用。

foreach $sub (@arr){
      print "Calling $sub\n";
       #---How to call $sub?----
       &$sub;  ## will not work
}

2 个答案:

答案 0 :(得分:10)

您的代码通常是正确的,但您需要关闭strict 'refs'以使Perl允许您将变量内容用作代码引用。

use strict;
use warnings;

sub foo { print "foo" }
sub bar { print "bar" }

my @arr = qw/foo bar/;
foreach my $sub (@arr) {
    no strict 'refs';
    print "Calling $sub\n";

    &$sub();
}

这里的输出是:

Calling foo
fooCalling bar
bar

我在调用后还添加了括号()。这样我们就不会向%$sub传递任何参数。如果我们不这样做,将使用当前子例程的@_参数列表。

但是,您可能不应该这样做。特别是如果@arr包含用户输入,这是一个大问题。您的用户可以注入代码。考虑一下:

my @arr = qw/CORE::die/;

现在我们得到以下输出:

Calling CORE::die
Died at /home/code/scratch.pl line 1492.

糟糕。你不想这样做。 die示例并不是很糟糕,但是像这样你可以轻松地在一些不合适的包中调用代码。

制作dispatch table可能更好。关于Mark Jason Dominus的 Higher Order Perl 中有一整章,你可以download for free on his website

它基本上意味着您将所有subs作为代码引用放入哈希,然后在循环中调用它们。这样你就可以控制哪些是允许的。

use strict;
use warnings;

sub baz { print "baz" }

my %dispatch = (
    foo => sub { print "foo" },
    bar => sub { print "bar" },
    baz => \&baz,
);

my @arr = qw/foo bar baz wrong_entry/;
foreach my $sub ( @arr ) {
    die "$sub is not allowed" 
        unless exists $dispatch{$sub};

    $dispatch{$sub}->();
}

输出:

foobarbaz
wrong_entry is not allowed at /home/code/scratch.pl line 1494.

答案 1 :(得分:7)

您希望使用代码引用来实现。

foreach my $sub (@arr) 
{
    $sub->();
}

其中@arr包含标量,例如

my $rc = sub { print "Anonymous subroutine\n" };

sub func { print "Named sub\n" }
my $rc = \&func;

您可以像处理任何其他标量一样操纵这些标量,以形成阵列。但是,将它们用作散列中的值更为常见和有用,创建调度表

请参阅perlref创建代码参考,this post也可能有所帮助。