如何遍历Perl中的函数列表?

时间:2009-08-05 07:32:02

标签: perl function loops

我在Perl中有一个函数列表。例如:

my @funcs = qw (a b c)

现在他们都属于这个模块Foo :: Bar :: Stix。我想在循环中迭代地调用它们:

foreach $func (@funcs) {
    Foo::Bar::Stix::$func->(%args)
}

其中args是参数的哈希值。但是我一直收到这个错误:“包含Foo :: Bar :: Stix :: $ func->(%args)的行之后的”...之后的错误名称“如何修复此错误?

a b和c不是函数对象而是字符串

5 个答案:

答案 0 :(得分:9)

不是将函数的名称存储在数组中,而是在散列中存储对它们的引用,以便您可以按名称引用它们。这是一个简单的代码示例:

#!/usr/bin/perl

use strict;
use warnings;

my %func_refs = (
    'a' => \&Foo::Bar::Stix::a,
    'b' => \&Foo::Bar::Stix::b,
    'c' => \&Foo::Bar::Stix::c
);

foreach my $func_ref ( values %func_refs ) {
    print $func_ref->( "woohoo: " ), "\n";
}

{
  package Foo::Bar::Stix;

  sub a {
    my $arg = shift;
    return $arg . "a";
  }

  sub b {
    my $arg = shift;
    return $arg . "b";
  }

  sub c {
    my $arg = shift;
    return $arg . "c";
  }
}

如果您因某种原因而无法存储名称,请尝试以下操作:

my $package    = "Foo::Bar::Stix";
my @func_names = qw/ a b c /;
foreach my $func_name (@func_names) {
    my $str = &{ "$package\::$func_name" }( "woohoo: " );
    print $str, "\n";
}

但是,这在use strict下不起作用,因此我更喜欢第一种解决方案。无论你做什么,尽量避免使用eval。这是不必要的,可能只会导致你的问题。

此外,大多数使用Perl的人将其资本化为Perl而不是PERL。这是关于这个主题的Stackoverflow问题:

How should I capitalize Perl?

答案 1 :(得分:3)

答案不好:使用符号引用:

for $func (@funcs) {
    &{"Foo::Bar::Stix::$func"}(\%args);
}

答案很好:使用调度表:

my %call_func = (
    'a' => \&Foo::Bar::Stix::a,
    'b' => \&Foo::Bar::Stix::b,
    'c' => \&Foo::Bar::Stix::c,
);
...
for $func (@funcs) {
    $call_func{$func}->(\%args);
}

答案 2 :(得分:1)

语法的轻微更改将为您提供所需的内容

Foo::Bar::Stix->$func(%args)

虽然这会将包名称作为第一个参数传递。

答案 3 :(得分:1)

您可以使用can

my @funcs = qw (a b c)
foreach $func (@funcs) {
    Foo::Bar::Stix->can($func)->(%args)
}

答案 4 :(得分:0)

您可以通过特殊的%Foo::Bar::Stix::变量访问它。这样可以直接完全访问符号表。您还会注意到它在严格模式下工作。

#! /usr/bin/env perl
use strict;
use warnings;

{
  package Foo::Bar::Stix;
  sub a{ print "sub a\n" }
  sub b{ print "sub b\n" }
  sub c{ print "sub c\n" }
}

my @funcs = qw' a b c ';
my %args;

for my $func (@funcs) {
  $Foo::Bar::Stix::{$func}->(%args); # <====
}

另一种选择:

my $symbol_table = $::{'Foo::'}{'Bar::'}{'Stix::'};

my %funcs = (
  # we only want the CODE references
  'a' => *{ $symbol_table->{'a'} }{'CODE'},
  'b' => *{ $symbol_table->{'b'} }{'CODE'},
  'c' => *{ $symbol_table->{'c'} }{'CODE'},
);

for my $func (@funcs) {
  $funcs{$func}->(%args); # <====
}

如果您要为大量子例程执行此操作,那么我将加载%funcs变量。

my %funcs;
BEGIN{
  my $symbol_table = $::{'Foo::'}{'Bar::'}{'Stix::'};

  for my $name (qw' a b c '){
    $funcs{$name} = *{ $symbol_table->{$name} }{'CODE'};
  }
}

除非你需要子程序同时拥有一个完全限定的名称,并通过一个哈希变量访问它,否则我不会这样做。

如果您只需要通过哈希变量访问子程序,这是设置它的更好方法。

my %funcs = (
  'a' => sub{ print "sub a\n" },
  'b' => sub{ print "sub b\n" },
  'c' => sub{ print "sub c\n" },
);

注意: 您可以将“my %funcs”替换为“our %funcs