将子例程分配给标量时的Perl继承或类似效果

时间:2014-08-20 12:50:31

标签: perl callback

我想将一个子标记分配给一个标量作为回调,同时归档继承行为,例如在下面的代码中调用foobar->warning()foobar->croaking()将触发父级的功能,如果没有实施在foobar类中提供。根据附加要求,我可以将其分配给标量。

我能解决这个问题的唯一方法是反过来,即调用' warning_check_child'在' barqux'这将检查特定实现是否可用或执行自己的代码。

我希望那里有人有更好的解决方案,所以我可以在开始时避免现有的电话,或者至少确认没有更好的方法。

提前致谢

use strict;
use warnings;

warn "When methods accessed as class from foobar";    
foobar->warning();

my $sub;
# assign class method to sub reference does not work
# $sub = \&foobar->warning;
# $sub->();

# Have the sub in other package check for custom functionality
$sub = \&barqux::warning_check_child;
$sub->();

### Child class
package foobar;
use parent -norequire, 'barqux';

sub warning{
    warn "warning: foobar\n";
}  
sub warning_check_child{
    warn "warning: foobar";
}

### Parent class
package barqux;

sub warning{
    warn "warning: barqux\n";
}  
sub croaking{
    warn "croaking: barqux\n";
}
sub warning_check_child{
    if ( exists &foobar::warning_check_child ){
        foobar::warning_check_child()
    }
    else {
        warn "warning: barqux\n";
    }
}

2 个答案:

答案 0 :(得分:4)

听起来你需要UNIVERSAL::can,如果类可以直接或通过继承执行该方法,它会向方法返回引用

喜欢这个

use strict;
use warnings;

my $sub = FooBar->can('warning_check_child');
$sub->();


### Parent class
package BarQux;

sub warning{
   warn "warning: BarQux\n";
}  

sub croaking{
   warn "croaking: BarQux\n";
}    

sub warning_check_child{
   warn "warning_check_child: BarQux\n";
}


### Child  class
package FooBar;
use base 'BarQux';

sub croaking{
   warn "croaking: FooBar\n";
}    

<强>输出

warning_check_child: BarQux

答案 1 :(得分:1)

回调是代码引用,Perl对象是有福的引用,因此您可以保佑CODE引用以创建具有继承的回调。如果您将Foo::warning转换为工厂,我认为您可以获得您之后的行为。

use 5.016; # needed for __SUB__
use strict;
use warnings;

package Bar {
    sub warning {
        my $class = shift;
        my $self  = sub {
            __SUB__->warning_check_child();
            say 'Bar::warning';
        };
        return bless $self, $class;
    }

    sub warning_check_child {
        my $self = shift;
        say 'Bar::warning_check_child';
    }
}

package Foo {
    use base 'Bar';

    sub warning {
        my $class = shift;
        my $self  = sub {
            __SUB__->warning_check_child();
            say 'Foo::warning'
        };
        return bless $self, $class;
    }
}

package main {
    my $f = Foo->warning();
    $f->();
}

输出

Bar::warning_check_child
Foo::warning

如果Foo添加warning_check_child方法,则会调用该方法。

注意:我在这里使用__SUB__作为编写$self的另一种方式,因为该对象是子例程。如果您仅限于5.16之前的Perl版本,则可以先预先声明$self,然后在其上创建一个闭包:

sub warning {
    my $class = shift;
    my $self;
    $self = sub {
        $self->warning_check_child();
        say 'Foo'
    };
    return bless $self, $class;
}