【问题标题】:Implementing a dispatch table实现调度表
【发布时间】:2020-01-04 15:23:07
【问题描述】:

我正在尝试实现一个调度表,它调用 Perl 模块中的函数。我一般都知道如何实现调度表,但是当从 $self 中引用对象方法时,我似乎无法正确理解它。也许我的谷歌搜索不够,但到目前为止,正确的语法是难以捉摸的。

我已经通过调用跟踪了参数,并且我知道发生了什么——函数引用没有接收到对 $self 的引用作为它们的第一个参数。这就是我目前在 $self 中的内容。我相信我正确地复制了这个;如果我犯了一个错误并且它没有运行,我很抱歉。

package MyRefHashTest;

use strict;
use warnings;

sub new {
    my $class = shift;
    my $self = {
        DISPATCH => {
            ONE => \&funcOne,
            TWO => \&funcTwo,
            THREE => \&funcThree,
            FOUR => \&funcFour
        }
    };

    bless $self, $class;
    return $self;
}

sub funcOne {
    my ($self, $param) = @_;
    print "func1 $param \n";
}

sub funcTwo {
    my ($self, $param) = @_;
    print "func2 $param \n";
}

sub funcThree {
    my ($self, $param) = @_;
    print "func3 $param \n";
}

sub funcFour {
    my ($self, $param) = @_;
    print "func4 $param \n";
}

sub runTesting {
    my ($self, $type) = @_;
    ($self->{DISPATCH}{$type} || sub {})->("string");
}

1;

# To Test:
$test = MyRefHashTest->new;
$test->runTesting("ONE");
$test->runTesting("TWO");
$test->runTesting("THREE");
$test->runTesting("FOUR");

我得到的实际输出是,$param 在调度表的函数调用中未定义,而它不应该是。这就是我知道对 $self 的引用不是它们应该在的地方的方式。函数认为 $type 是 $self。

我已尝试编辑哈希表引用,使其看起来像 \$self->functionName,但这只会导致 $self 在该行上没有正确定义的编译错误。

谁能指导我使用正确的语法吗?

谢谢!

编辑:经过更多的工作,我终于找到了解决方案。这是一些非常有趣的语法,比我想象的要复杂得多。本质上,我是从内向外构建哈希:

    my $self = {
        DISPATCH => undef
    };
    $self->{DISPATCH} = {
        ONE => sub { $self->funcOne(@_); },
        TWO => sub { $self->funcTwo(@_); },
        THREE => sub { $self->funcThree(@_); },
        FOUR => sub { $self->funcFour(@_); }
    };

它有效,但它似乎很麻烦。如果有人知道更简单的方法来做到这一点,我仍然会对它非常感兴趣。另一方面,如果没有更简单的方法,我希望这可以帮助某人。

【问题讨论】:

    标签: perl hash reference


    【解决方案1】:

    以下是实现基于方法的调度表的四种方法。后面会解释不同之处。

    my %DISPATCH = (
        ONE   => \&funcOne,
        TWO   => \&funcTwo,
        THREE => \&funcThree,
        FOUR  => \&funcFour,
    );
    
    sub runTesting {
        my ($self, $type) = @_;
        my $method = $DISPATCH{$type};
        return $self->$method("string");
    }
    

    my %DISPATCH = (
        ONE   => __PACKAGE__->can('funcOne'),
        TWO   => __PACKAGE__->can('funcTwo'),
        THREE => __PACKAGE__->can('funcThree'),
        FOUR  => __PACKAGE__->can('funcFour'),
    );
    
    sub runTesting {
        my ($self, $type) = @_;
        my $method = $DISPATCH{$type};
        return $self->$method("string");
    }
    

    my %DISPATCH = (
        ONE   => 'funcOne',
        TWO   => 'funcTwo',
        THREE => 'funcThree',
        FOUR  => 'funcFour',
    );
    
    sub runTesting {
        my ($self, $type) = @_;
        my $method_name = $DISPATCH{$type};
        return $self->$method_name("string");
    }
    

    my %DISPATCH = (
        ONE   => sub { shift->funcOne(@_) },
        TWO   => sub { shift->funcTwo(@_) },
        THREE => sub { shift->funcThree(@_) },
        FOUR  => sub { shift->funcFour(@_) },
    );
    
    sub runTesting {
        my ($self, $type) = @_;
        my $cb = $DISPATCH{$type};
        return $cb->($self, "string");
    }
    

    所有四种方法都允许在同一个类中定义方法。

    最后三种方法也允许在超类中定义方法。

    最后两种方法也允许子类提供或覆盖该方法。这些是您的最佳选择。

    【讨论】:

    • 嘿@ikegami。这是来自 Perlmonks 的 holli。我正在尝试参与 SO,但我很难适应这里人们的态度。帖子正在被编辑,完美的问题一直被搁置,我刚刚看到你的帖子在这里被否决了。你是怎么处理的?
    • @Holli,我的回答中有一个错误。这可能就是它被否决的原因。如果有人告诉我,我会很感激的,但幸运的是,我想通了并修复了它。
    • 在这里高度关注问答质量,这可能经常被过度使用。尽管如此,这是一个非常有用的网站。
    • 感谢ikegami的详细解答! :)
    • 如果这可以令人满意地回答您的问题,请勾选旁边的标记。
    【解决方案2】:

    在动态调度方法中传入$self怎么样:

    sub runTesting {
        my ($self, $type) = @_;
        ($self->{DISPATCH}{$type} || sub {})->($self,"string");
                                               ^^^^^
    }
    

    我认为问题在于您将方法作为普通函数而不是对象方法来调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多