2009-08-05 63 views
4

我有一个Perl函数列表。例如:如何循环访问Perl中的函数列表?

my @funcs = qw (a b c) 

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

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

其中args是参数的散列。然而,我不断收到这个错误:“包括Foo :: Bar :: Stix :: $ func - >(%args)”的行后出现“Bad name after ... ...”如何修复此错误?

一个B和C都没有函数对象,但字符串

回答

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?

+3

+1用于链接到大小写问题。如果你认为Perl是PERL,你的业力将会非常糟糕,以至于没有什么可行的。 – innaM 2009-08-05 08:46:37

+1

`$ Foo :: Bar :: Stix :: {$ func} - >(%args);`也可以工作,并且不需要关闭严格。 – 2009-08-12 15:55:04

1

语法稍有变化会给你你想要

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

虽然这会通过包名作为第一个参数是什么。

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); 
} 
+0

我完全同意你的看法,我说在我的答案相同。 – 2009-08-05 08:25:33

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

1

您可以使用can

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