如何使用哈希在 Perl 中创建回调函数(调度表)?

发布于 2024-12-01 22:04:59 字数 607 浏览 0 评论 0原文

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

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{
...
}

一个警告是子函数是在其他模块中定义的,因此回调必须能够引用它们......加上 我很难得到正确的哈希值!

I want to call a main controller function that dispatches other function dynamically, something like this:

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{
...
}

One caveat is that the subs are defined in other Modules, so the callbacks would have to be able to reference them... plus
I'm having a hard time getting the hashes right!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

a√萤火虫的光℡ 2024-12-08 22:04:59

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

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

您可以在散列中插入更多散列值:

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

您可以像这样调用一个散列值

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

或者

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

您可以从 STDIN 或其他任何地方获取散列键。

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

sub delete {
    # regular sub definition
}

$callbacks{delete} = \&delete;

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

您的代码也充满了语法错误,这可能会掩盖这里更深层次的问题。我也不清楚你想对第二级数组做什么。您何时定义这些子系统?谁在何时使用它们?用于什么目的?

So, it's possible to have a hash that contains anonymous subroutines that you can invoke from stdin.

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

And you can insert more hashvalues into the hash:

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

And you would invoke one like this

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

Or

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

You can get the hashkey from STDIN, or anywhere else.

You can also define them nonymously and then take a reference to them.

sub delete {
    # regular sub definition
}

$callbacks{delete} = \&delete;

I wouldn't call these callbacks, however. Callbacks are subs that get called after another subroutine has returned.

Your code is also rife with syntax errors which may be obscuring the deeper issues here. It's also not clear to me what you're trying to do with the second level of arrays. When are you defining these subs, and who is using them when, and for what?

人│生佛魔见 2024-12-08 22:04:59

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

# 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   => \÷,
    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";
}

Perhaps this simplified example will help:

# 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   => \÷,
    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";
}
薔薇婲 2024-12-08 22:04:59

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

当然,演示这一点需要多个文件,我正在使用

dispatch_core.pl:DTable/Add.pm:DTable/MultDiv.pm

#!/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);
}

添加

package DTable::Add;

use strict;
use warnings;

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

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

1;

package DTable::MultDiv;

use strict;
use warnings;

sub dispatchable {
    return (multiply => \&multiply, 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);
}   

You've already got some good answers on how to build a dispatch table and call functions through it within a single file, but you also keep talking about wanting the functions to be defined in other modules. If that's the case, then wouldn't it be better to build the dispatch table dynamically based on what dispatchable functions each module says it has rather than having to worry about keeping it up to date manually? Of course it would!

Demonstrating this requires multiple files, of course, and I'm using Module::Pluggable from CPAN to find the modules which provide the function definitions.

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 => \÷);
}

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

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

1;

Then, on the command line:

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

Adding new functions is now as simple as dropping a new file into the DTable directory with an appropriate dispatchable sub. No need to ever touch dispatch_core.pl just to add a new function again.

Edit: In response to the comment's question about whether this can be done without Module::Pluggable, here's a modified dispatch_core.pl which doesn't use any external modules other than the ones defining the dispatchable functions:

#!/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);
}   
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文