Base.pm
:
package Base;
use Moose::Role;
sub f {
my ($self) = @_;
print "In role.\n";
}
1;
X.pm
:
package X;
use Moose;
with 'Base';
around 'f' => sub {
my ($next, $self) = @_;
print "Nevermind, we are in class X.\n";
};
__PACKAGE__->meta->make_immutable;
1;
Y.pm
:
package Y;
use Moose;
with 'Base';
override 'f' => sub {
my ($self) = @_;
print "Nevermind, we are in class Y.\n";
};
__PACKAGE__->meta->make_immutable;
1;
然后X确实有效,Y没有。这是一个奇怪的设计,因为override
只是around
的一个特例,并且特殊情况也应该起作用。
任何人都可以解释为什么这个设计决定以及它为何如此奇怪?
$ perl X.pm
$ perl Y.pm
Cannot add an override method if a local method is already present at /usr/lib/i386-linux-gnu/perl5/5.22/Moose/Exporter.pm line 419
Moose::override('f', 'CODE(0x9c002f8)') called at Y.pm line 9
答案 0 :(得分:3)
documentation describes override
为:
覆盖方法是一种明确说“我从我的超类中覆盖此方法”的方法。您可以在此方法中调用
super
,它将按预期工作。使用普通方法调用和SUPER::
伪包可以完成同样的事情;这真的是你的选择。
你在做什么与这个定义相矛盾。使用角色,您的包中会安装f
。您正尝试在同一个包中定义另一个f
。
你的角色被称为Base
这一事实向我表明,当谈到继承与构成之间的区别时,你会有一些困惑。
purpose of around
是在当前类中包装一个方法,无论它是在同一个包中实现还是继承或组合:
方法修饰符可用于向方法添加行为,而无需修改这些方法的定义。
只需简单地阅读这两个片段就可以让我明白这一点。
当您应用定义f
的角色时,它本身会覆盖任何继承的方法f
。如果您再说override 'f'
,则表示您打算再次覆盖f
。好吧,一个类中只能有一个方法f
。哪一个应该算?通过应用角色或刚刚定义的角色获得的角色?对于所有意图和目的,组成角色所获得的方法就像您在类中手动定义的方法一样。没有理由a priori
一个比另一个更重要。
将此视为航空旅行。将方法修饰符视为类:首先,商业,经济等等。因此,在第一类中,get_dinner_menu
可能包含开胃菜,糖果,甜点等。
另一方面,override
就像改变航班一样。这就好像你说“我想要在TK 1和UIA 213上飞行”。毫无意义。
通过显示around
的简单实现并在不使用override
的情况下覆盖方法,以下脚本可能会使事情变得更清晰。
#!/usr/bin/env perl
use strict;
use warnings;
{
package MyRole;
use Moose::Role;
sub f {
print "in role\n";
}
}
{
package X;
use Moose;
with 'MyRole';
around 'f' => sub {
my ($orig, $self) = @_;
print "In wrapper\n";
return $self->$orig( @_ );
};
{
my $f = \&f;
{
no warnings 'redefine';
*f = sub {
my ($self) = @_;
print "In wrapper wrapper\n";
return $self->$f( @_ );
}
}
}
}
{
package Y;
use Moose;
with 'MyRole';
sub f {
print "In overridden method\n";
}
}
print '=-=' x 22, "\n";
my $x = X->new;
$x->f;
print '=-=' x 22, "\n";
my $y = Y->new;
$y->f;
输出:
=-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-= In wrapper wrapper In wrapper in role =-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-= In overridden method