How do I implement a dispatch table in a Perl OO module?

后端 未结 4 769
轮回少年
轮回少年 2020-12-31 15:21

I want to put some subs that are within an OO package into an array - also within the package - to use as a dispatch table. Something like this

package Blah:         


        
4条回答
  •  耶瑟儿~
    2020-12-31 16:10

    Your friend is can. It returns a reference to the subroutine if it exists, null otherwise. It even does it correctly walking up the OO chain.

    $self->{tests} = [
        $self->can('_sub1'),
        $self->can('_sub2'),
    ];
    
    # later
    
    for $tn (0..$#{$self->{tests}}) {
        ok defined $self->{tests}[$tn], "Function $tn is available.";
    }
    
    # and later
    
    my $ref = $self->{tests}[0];
    $self->$ref(@args1);
    $ref = $self->{tests}[1];
    $self->$ref(@args2);
    

    Or, thanks to this question (which happens to be a variation of this question), you can call it directly:

    $self->${\$self->{tests}[0]}(@args1);
    $self->${\$self->{tests}[1]}(@args1);
    

    Note that the \ gives us a reference to a the subref, which then gets dereferenced by the ${} after $self->. Whew!

    To solve the timeliness issue brain d foy mentions, an alternative would be to simply make the {test} a subroutine itself, that returns a ref, and then you could get it at exactly the time you need it:

    sub tests {
        return [ 
            $self->can('_sub1'),
            $self->can('_sub2')
        ];
    }
    

    and then use it:

    for $tn (0..$#{$self->tests()}) {
       ...
    }
    

    Of course, if you have to iterate over the refs anyway, you might as well just go straight for passing the reference out:

    for my $ref (0..$#{$self->tests()}) {
        $self->$ref(@args);
    }
    

提交回复
热议问题