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

est*_*est 1 perl

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

use Foo ();  

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

Foo::init(%config);

sub my_error {
    my ($message) = @_;
    ...
}
Run Code Online (Sandbox Code Playgroud)

但是,my_error()当我用OO样式作为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) = @_;
    ...
}
Run Code Online (Sandbox Code Playgroud)

我该如何解决?通过&{ $self->my_error }似乎不起作用.

谢谢!

ike*_*ami 7

如果您在没有sub时需要sub,则需要制作sub.你可以做一个匿名的.

sub { $self->my_error(@_) }
Run Code Online (Sandbox Code Playgroud)

这意味着

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

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

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

但这会造成内存泄漏.子捕获$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(@_) },
        },
    );
}
Run Code Online (Sandbox Code Playgroud)

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

use curry::weak qw( );

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

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