Moose::Role 带有重写方法的怪异
Posted
技术标签:
【中文标题】Moose::Role 带有重写方法的怪异【英文标题】:Moose::Role weirdness with overridden methods 【发布时间】:2016-06-30 16:46:55 【问题描述】: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
【问题讨论】:
【参考方案1】:documentation describes override
为:
覆盖方法是一种明确表示“我正在从我的超类中覆盖此方法”的方式。您可以在此方法中调用
super
,它将按预期工作。同样的事情可以通过普通的方法调用和SUPER::
伪包来完成;这真的是你的选择。
你所做的与这个定义相矛盾。使用角色,f
安装在您的包中。您正试图在同一个包中定义另一个 f
。
你的角色被称为Base
这一事实向我表明,当谈到继承与组合之间的区别时,你有些困惑。
purpose of around
是在当前类中包装一个方法,不管是在同一个包中实现还是继承或组合:
方法修饰符可用于向方法添加行为,而无需修改这些方法的定义。
只要简单地阅读这两个 sn-ps,我就可以清楚地区分它们。
当您应用定义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;
输出:
=-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==- ==-==-==-==-==-==-= 在包装器中 在包装中 在角色中 =-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==- ==-==-==-==-==-= 在被覆盖的方法中
【讨论】:
但是为什么在地球上,around
在这种情况下确实有效?不能对around
说同样的话来证明它不应该工作吗?
知道了。但是允许 both sub
和 around
在一个类中使用相同的方法对我来说似乎是一个设计错误
在同一个包中禁止 sub f
和around 'f'
没有任何好处,因为组成一个提供@987654347 的角色@ 将 f
安装为包中的子项。因此,该禁令使得将around
与组合方法一起使用变得不可能或困难。我没有想太多。以上是关于Moose::Role 带有重写方法的怪异的主要内容,如果未能解决你的问题,请参考以下文章