我在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不是函数对象而是字符串
答案 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问题:
答案 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
”