我使用了一个我无法控制的外部模块(比如说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 }似乎不起作用.
谢谢!
如果您在没有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)
但我认为这只会增加混乱.