假如我有一个子过程,定义如下:

sub test_sub {
    print "test";
}

我又有一个变量:

$test = "test_sub";

这个 $test 的值刚好就是上面子过程的名称。既然我通过 $test 知道了这个子过程名称,我可以通过 $test 达到调用这个子过程的目的吗?也就是说,我让用户从命令行里输入一个子过程的名称,然后就可以根据这个名称来调用相对应的子过程。

方法一,直接根据用户输入的子过程名来调用该子过程。

完整的例子代码如下:

use warnings;
no strict 'refs';

sub test_sub {
    print "test";
}

$test = "test_sub";

$test->();

&{$test}();  #anyway to invoke the subroutine

这里要注意,需要用

no strict 'refs';

这个语句,否则脚本不能运行,Perl 解释器会提示类似于下面的错误:

Global symbol “$test” requires explicit package name at test2.pl line 10.

方法二,更常规的做法是专门用一个起分派作用的散列,根据用户输入的请示而调用相应的子过程。例如下面的 %dispatcher 就起到了绑定识别标记与相应子过程引用的作用,通过这个唯一的标记 (key),我们可以很容易地找到对应的子过程引用

my %dispatcher = (
    sub_test => sub { print "test" },
);

然后可以用和方法一相同的语法来调用这个子过程:

$dispatcher{$sub_name}->();

下面是方法二的一个完整的例子:

use warnings;
use strict;

sub test_sub {
    print "test\n";
}

sub test_other {
    print "test other\n";
}

my %dispatcher = (
                  "test_sub"     => \&test_sub,
                  "test_other"   => \&test_other,
                 );

print "\nPlease enter the test case you want to test:\n";

while( my $cmd = <> )
{
    chomp($cmd);

    $dispatcher{$cmd}->() if exists $dispatcher{$cmd};
}

当然,方法二要比方法一优秀得多,它可以避免用户输入错误的子过程名而导致一系列的麻烦。