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

Raj*_*Raj 5 perl call subroutine

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

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

sim*_*que 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();
}
Run Code Online (Sandbox Code Playgroud)

这里的输出是:

Calling foo
fooCalling bar
bar
Run Code Online (Sandbox Code Playgroud)

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


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

my @arr = qw/CORE::die/;
Run Code Online (Sandbox Code Playgroud)

现在我们得到以下输出:

Calling CORE::die
Died at /home/code/scratch.pl line 1492.
Run Code Online (Sandbox Code Playgroud)

哎呀.你不想这样做.这个die例子并不是很糟糕,但是像这样你可以很容易地在一些不合适的包中调用代码.

制作调度表可能更好.关于Mark Jason Dominus的高阶Perl中有一整章,您可以在他的网站上免费下载.

它基本上意味着您将所有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}->();
}
Run Code Online (Sandbox Code Playgroud)

这输出:

foobarbaz
wrong_entry is not allowed at /home/code/scratch.pl line 1494.
Run Code Online (Sandbox Code Playgroud)


zdi*_*dim 8

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

foreach my $sub (@arr) 
{
    $sub->();
}
Run Code Online (Sandbox Code Playgroud)

其中@arr包含诸如的标量

my $rc = sub { print "Anonymous subroutine\n" };
Run Code Online (Sandbox Code Playgroud)

要么

sub func { print "Named sub\n" }
my $rc = \&func;
Run Code Online (Sandbox Code Playgroud)

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

请参阅perlref以创建代码引用,此帖也可能有所帮助.