我使用了一个我无法控制的外部模块(比如 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 }
似乎不起作用。
谢谢!
答案 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中对其工作方式给出了合理的解释。