【问题标题】:How to call subroutine in perl using variable name [duplicate]如何使用变量名在perl中调用子程序[重复]
【发布时间】:2017-05-19 19:15:07
【问题描述】:

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

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

【问题讨论】:

  • (\&$name)->(@args)

标签: perl call subroutine


【解决方案1】:

您想使用代码引用来做到这一点。

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

其中@arr 包含标量,例如

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

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

您可以像操作其他任何标量一样操作这些标量,以形成您的数组。然而,将它们用作散列中的值,创建一个调度表更为常见和有用。

请参阅 perlrefperlsub,以及(例如)this post 以及其中的链接以了解 cmets 和详细信息。

【讨论】:

    【解决方案2】:

    您的代码总体上是正确的,但是您需要关闭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
    • @Zaid 哦,还有两个答案。我还没有看到他们。我只是忙着再次在这里写半篇博客文章......:D
    • 嗨辛巴克。谢谢。我不知道。在我的情况下,用户没有在参数中提供子例程名称,而是提供很好的信息。
    • @Zaid 我假设 OP 没有use strict,因为循环中没有my sub。在这种情况下,OP 的代码有效。但是,在打开 strict 后,需要禁用 strict 'refs'
    • 我是不是因为文字太多而被否决了?
    猜你喜欢
    • 2017-02-19
    • 2010-12-27
    • 1970-01-01
    • 2010-12-05
    • 2013-02-15
    • 2020-09-22
    • 2021-07-10
    • 2013-08-26
    相关资源
    最近更新 更多