将代码引用传递给外部模块

时间:2015-07-30 15:27:37

标签: perl

我使用了一个我无法控制的外部模块(比如 Foo.pm )。使用它的方式如下,工作正常:

use Foo ();  

my %config = (
    MODE  => 'NORMAL',
    ERROR => \&my_error,    # error handling routine
);

Foo::init(%config);

sub my_error {
    my ($message) = @_;
    ...
}

但是当我用OO样式编写时,我将my_error()传递给外部模块时因为my_error()的第一个参数现在是$self

package MyPackage;
use Foo ();

sub new {
    my $self = bless {
        environment => 'TEST',
        config      => {
            MODE  => 'NORMAL',
            ERROR => \&my_error,   # WRONG ??!
        },
    }, __PACKAGE__;

    Foo::init( %{$self->{config}} );
}

sub my_error {
    my ($self, $message) = @_;
    ...
}

我该如何解决?传递&{ $self->my_error }似乎不起作用。

谢谢!

2 个答案:

答案 0 :(得分:7)

如果你需要一个sub,当你没有sub时,你需要制作一个sub。你可以做一个匿名的。

sub { $self->my_error(@_) }

这意味着

my $self = bless {
    environment => 'TEST',
    config      => {
        MODE  => 'NORMAL',
        ERROR => sub { $self->my_error(@_) },
    },
}, $class;

但是有并发症。在您的代码中,当您尝试捕获它时,$self尚未声明。修正:

my $self = bless({}, $class);
%$self = (
    environment => 'TEST',
    config      => {
        MODE  => 'NORMAL',
        ERROR => sub { $self->my_error(@_) },
    },
);

但这会造成内存泄漏。子捕获$self,它引用包含对sub的引用的哈希。修正:

use Scalar::Util qw( weaken );

my $self = bless({}, $class);
{
    weaken( my $self = $self );
    %$self = (
        environment => 'TEST',
        config      => {
            MODE  => 'NORMAL',
            ERROR => sub { $self->my_error(@_) },
        },
    );
}

正如simbabque指出的那样,curry::weak模块可以简化(?)这一点。

use curry::weak qw( );

my $self = bless({}, $class);
%$self = (
    environment => 'TEST',
    config      => {
        MODE  => 'NORMAL',
        ERROR => $self->curry::weak::my_error(),
    },
);

但我认为这只会增加混乱。

答案 1 :(得分:4)

ikegami's excellent and detailed answer最后一部分的一个很好的替代方法是使用curry::weak

use curry::weak;

my $self = bless({}, $class);
%$self = (
    environment => 'TEST',
    config      => {
        MODE  => 'NORMAL',
        ERROR => $self->curry::weak::my_error(),
    },
);
curry的作者mst在this lightning talk中对其工作方式给出了合理的解释。