6

我想调用一个动态调度其他函数的主控制器函数,如下所示:

package Controller;

my %callback_funcs = ();

sub register_callback{
   my ($class,$callback,$options) = _@;
   #apppend to %callback_funcs hash ... ?
}

sub main{
%callback_funcs = ( add => 'add_func', rem => 'remove_func', edit => 'edit_func');  
  while(<STDIN>){
     last if ($_ =~ /^\s*$/);
     if($_ == 'add' || _$ == 'rem' || _$ == 'edit'){
        $result = ${callback_funcs['add']['func']}(callback_funcs['add']['options']);
     }
  }
}

sub add_func{
...
}

一个警告是 subs 是在其他模块中定义的,所以回调必须能够引用它们......另外,我很难得到正确的哈希值!

4

3 回答 3

15

因此,可以有一个包含匿名子例程的哈希,您可以从标准输入调用这些子例程。

my %callbacks = (
    add => sub {
        # do stuff
    },
    fuzzerbligh => sub {
        # other stuff
    },
);

您可以在哈希中插入更多哈希值:

$callbacks{next} = sub {
    ...
};

你会像这样调用一个

$callbacks{next}->(@args);

或者

my $coderef = $callbacks{next};
$coderef->(@args);

您可以从 STDIN 或其他任何地方获取 hashkey。

您还可以匿名定义它们,然后引用它们。

sub delete {
    # regular sub definition
}

$callbacks{delete} = \&delete;

但是,我不会调用这些回调。回调是在另一个子例程返回后调用的子程序。

您的代码也充斥着语法错误,这可能会掩盖这里更深层次的问题。我也不清楚您要对第二级数组做什么。你什么时候定义这些潜艇,谁在什么时候使用它们,为了什么?

于 2011-08-30T01:28:14.977 回答
8

也许这个简化的例子会有所帮助:

# Very important.
use strict;
use warnings;

# Define some functions.
sub multiply { $_[0] * $_[1] }
sub divide   { $_[0] / $_[1] }
sub add      { $_[0] + $_[1] }
sub subtract { $_[0] - $_[1] }

# Create a hash of references to those functions (dispatch table).
my %funcs = (
    multiply => \&multiply,
    divide   => \&divide,
    add      => \&add,
    subtract => \&subtract,
);

# Register some more functions.
sub register {
    my ($key, $func) = @_;
    $funcs{$key} = $func;
}

register('+', \&add);    # As above.
register('sum', sub {    # Or using an anonymous subroutine.
    my $s = 0;
    $s += $_ for @_;
    return $s;
});

# Invoke them dynamically.
while (<>){
    my ($op, @args) = split;
    last unless $op and exists $funcs{$op}; # No need for equality tests.
    print $funcs{$op}->(@args), "\n";
}
于 2011-08-30T02:05:39.863 回答
7

关于如何在单个文件中构建调度表并通过它调用函数,您已经得到了一些很好的答案,但您还一直在谈论希望在其他模块中定义函数。如果是这种情况,那么根据每个模块所说的可调度功能动态构建调度表,而不是担心手动更新它不是更好吗?当然会!

当然,演示这需要多个文件,我正在使用CPAN 中的Module::Pluggable来查找提供函数定义的模块。

dispatch_core.pl:

#!/usr/bin/env perl

use strict;
use warnings;

my %dispatch;

use lib '.'; # a demo is easier if I can put modules in the same directory
use Module::Pluggable require => 1, search_path => 'DTable';
for my $plugin (plugins) {
    %dispatch = (%dispatch, $plugin->dispatchable);
}

for my $func (sort keys %dispatch) {
    print "$func:\n";
    $dispatch{$func}->(2, 5);
}

DTable/Add.pm:

package DTable::Add;

use strict;
use warnings;

sub dispatchable {
    return (add => \&add);
}

sub add {
    my ($num1, $num2) = @_;
    print "$num1 + $num2 = ", $num1 + $num2, "\n";
}

1;

DTable/MultDiv.pm:

package DTable::MultDiv;

use strict;
use warnings;

sub dispatchable {
    return (multiply => \&multiply, divide => \&divide);
}

sub multiply {
    my ($num1, $num2) = @_;
    print "$num1 * $num2 = ", $num1 * $num2, "\n";
}

sub divide {
    my ($num1, $num2) = @_;
    print "$num1 / $num2 = ", $num1 / $num2, "\n";
}

1;

然后,在命令行上:

$ ./dispatch_core.pl 
add:
2 + 5 = 7
divide:
2 / 5 = 0.4
multiply:
2 * 5 = 10

现在添加新函数就像使用适当的dispatchable子目录将新文件拖放到 DTable 目录中一样简单。无需触摸dispatch_core.pl即可再次添加新功能。

编辑:针对评论中关于是否可以在没有 Module::Pluggable 的情况下完成此操作的问题,这里有一个修改后的 dispatch_core.pl,它不使用除定义可调度函数的模块之外的任何外部模块:

#!/usr/bin/env perl

use strict;
use warnings;

my %dispatch;

my @dtable = qw(
  DTable::Add
  DTable::MultDiv
);

use lib '.';
for my $plugin (@dtable) { 
    eval "use $plugin";
    %dispatch = (%dispatch, $plugin->dispatchable);
}   

for my $func (sort keys %dispatch) {
    print "$func:\n";
    $dispatch{$func}->(2, 5);
}   
于 2011-08-30T10:10:52.607 回答