我有这样的代码:
package Foo;
use Moo;
has attr => ( is => "rw", trigger => 1 );
sub _trigger_attr
{ print "trigger! value:". shift->attr ."\n" }
package main;
use Foo;
my $foo = Foo->new( attr => 1 );
$foo->attr( 2 );
它会传回:
$ perl test.pl
trigger! value:1
trigger! value:2
这是Moo中触发器的默认记录行为。
如果属性是通过构造函数设置的,如何禁用触发器执行?
我当然可以这样做:
package Foo;
use Moo;
has attr => ( is => "rw", trigger => 1 );
has useTriggers => ( is => "rw", default => 0 );
sub _trigger_attr
{
my $self = shift;
print "trigger! value:". $self->attr ."\n" if $self->useTriggers
}
package main;
use Foo;
my $foo = Foo->new( attr => 1 );
$foo->useTriggers( 1 );
$foo->attr( 2 );
并得到:
$ perl testt.pl
trigger! value:2
所以它的工作,但......这感觉不对;).
3条答案
按热度按时间qco9c6ql1#
我不太了解
Moo
,但是在Moose
中,你可以在构造函数之后实现你自己的代码。如果你能在Moo
中这样做,它会给予你想要的效果。这将导致
useTriggers
在构造之后立即被设置,因此触发器将在构造对象之后而不是在构造对象之前处于活动状态。因此,您应该可以写入:
并获得相同的输出。
e0bqpujr2#
ffdz8vbo3#
因为Perl 5.36发布时签名不再是实验性的,所以
Moose
生态系统中的事情变得复杂了。对于
Moo
,没有任何更改,useTriggers技巧或构建自定义访问器仍然是有效答案。对于
Moose
和Mouse
,当通过属性访问器更改值时,也会传递旧值。因此,从构造函数调用的触发器和在现有属性上调用的触发器可以通过arity进行区分。常见模式为:使用签名有一个新的问题-如果使用了签名,就无法检查
@_
(这被认为是实验性的,会抛出一个警告,通常不鼓励这样做)。因此,当将签名适配到变量触发器子元数时,可能会陷入这个陷阱:仅当属性本身不能为
Undef
时,这才起作用否则,触发器将无法按预期在$object->attribute( undef );
改变。
这个笨拙的解决方案是故意将旧的param错误键入为slurpy array:
当通过属性访问器更改值时(属性是否可以为
Undef
无关紧要),它将正确激发,并且当从构造函数初始化时将激发并跳过逻辑。