2009-08-05 65 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) 
}