Perl 观察驼鹿属性的变化
在Moose中,当属性的内容通过引用而不是通过mutator设置其值时,是否有方法触发回调 让我们假设以下代码:Perl 观察驼鹿属性的变化,perl,moose,Perl,Moose,在Moose中,当属性的内容通过引用而不是通过mutator设置其值时,是否有方法触发回调 让我们假设以下代码: has _changed => ( is => 'rw' , isa=>'Bool' ) ; has attribute => ( is=>'rw', isa=>'Maybe[HashRef]', default => sub { { a => 1 , b => 2 } }, trigger
has _changed => ( is => 'rw' , isa=>'Bool' ) ;
has attribute => (
is=>'rw', isa=>'Maybe[HashRef]',
default => sub { { a => 1 , b => 2 } },
trigger => sub { shift->_changed(1) }
) ;
触发器按预期工作,通过mutator设置属性值:
$self->attribute({ a => 2 , b => 2 }) ; # OK
但是,如果通过其键直接设置值,则触发器不会触发(当然):
我放弃了创建(并比较)序列化属性内容摘要的想法,因为它可能是一个具有多个嵌套级别的非常庞大的hashref,并且在每个属性访问时生成摘要会产生性能问题
绑定的hashref(作为属性值)可能是一个可行的解决方案吗?
非常感谢您的任何想法或建议
注意:所包含的hashref的结构未知(我正在编写一个ORM类,因此结构可能会因存储在NOSQL db端的文档而异)。一旦您直接更改hash ref而不是使用访问器方法,Moose就不再参与其中。让属性返回对绑定哈希的引用将是对可观察哈希进行更改的唯一策略,但这并不是一个特别有吸引力的解决方案。绑定变量很少见,可能会在某些代码中触发bug。实施起来比较困难。它们意味着每次哈希访问都会产生性能开销
强烈地考虑是否可以更改设计以避免暴露内部散列。例如,有一个仅返回散列的(浅)副本的getter,以及散列中单个元素的setter。您可以使用
句柄
和特征
机制自动生成其中一些访问器,例如参见。一旦您直接更改哈希引用而不是使用访问器方法,Moose就不再参与。让属性返回对绑定哈希的引用将是对可观察哈希进行更改的唯一策略,但这并不是一个特别有吸引力的解决方案。绑定变量很少见,可能会在某些代码中触发bug。实施起来比较困难。它们意味着每次哈希访问都会产生性能开销
强烈地考虑是否可以更改设计以避免暴露内部散列。例如,有一个仅返回散列的(浅)副本的getter,以及散列中单个元素的setter。您可能能够使用
句柄
和特征
机制自动生成其中一些访问器,例如,请参见。以下基于Perl模块的方法演示了如何轻松监视Moose属性的更改,即使通过直接访问包含的hashref而不是使用适当的setter方法进行修改
package Test::Document ;
use Mouse ;
use Tie::Trace qw<watch> ;
has _changed => ( is => 'rw', isa => 'Bool' ) ;
...
has value => (
is => 'rw', isa => 'HashRef',
default => sub { { } },
trigger => sub { shift->_changed( 1 ) }
) ;
sub BUILD {
my ( $self ) = @_ ;
$self->_changed( 0 ) ; # reset flag
watch %{ $self->{ value } } , debug=> sub {
$self->_changed(1)
};
return $self ;
}
package main ;
my $doc = Test::Document->new( value => { a => 1 , b => { c => 3 } } ) ;
my $x = $doc->value->{ b }->{ e } ; # not changed
$doc->value->{ b }->{ e } = 4 ; # changed
$doc->_changed(0);
delete $doc->value->{ b }->{ e } ; # changed
$doc->_changed(0);
$doc->value({ a => 1 }) ; # changed
包测试::文档;
使用鼠标;
使用Tie::Trace qw;
是否已更改(is=>'rw',isa=>'Bool');
...
has value=>(
is=>'rw',isa=>'HashRef',
默认值=>sub{{},
触发器=>sub{shift->_changed(1)}
) ;
子构建{
我的($self)=@;
$self->_已更改(0)#重置标志
监视%{$self->{value}},调试=>sub{
$self->\u已更改(1)
};
返回$self;
}
主包装;
我的$doc=Test::Document->new(值=>{a=>1,b=>{c=>3});
我的$x=$doc->value->{b}->{e};#不变
$doc->value->{b}->{e}=4;#改变
$doc->\u已更改(0);
删除$doc->value->{b}->{e};#改变
$doc->\u已更改(0);
$doc->value({a=>1});#改变
优点:有效:)
缺点:递归绑定方法在具有大量键和嵌套级别的哈希上可能会产生性能问题。我必须做一些基准测试
注意:我尝试使用magic vars,但是使用类似
sub()->{a}->{b}
语法的标量上下文传播会强制触发store
事件,即使没有(显式)赋值。欢迎您提出建议。以下基于Perl模块的方法演示了如何轻松监视Moose属性更改,即使是通过直接访问包含的hashref而不是使用适当的setter方法进行修改
package Test::Document ;
use Mouse ;
use Tie::Trace qw<watch> ;
has _changed => ( is => 'rw', isa => 'Bool' ) ;
...
has value => (
is => 'rw', isa => 'HashRef',
default => sub { { } },
trigger => sub { shift->_changed( 1 ) }
) ;
sub BUILD {
my ( $self ) = @_ ;
$self->_changed( 0 ) ; # reset flag
watch %{ $self->{ value } } , debug=> sub {
$self->_changed(1)
};
return $self ;
}
package main ;
my $doc = Test::Document->new( value => { a => 1 , b => { c => 3 } } ) ;
my $x = $doc->value->{ b }->{ e } ; # not changed
$doc->value->{ b }->{ e } = 4 ; # changed
$doc->_changed(0);
delete $doc->value->{ b }->{ e } ; # changed
$doc->_changed(0);
$doc->value({ a => 1 }) ; # changed
包测试::文档;
使用鼠标;
使用Tie::Trace qw;
是否已更改(is=>'rw',isa=>'Bool');
...
has value=>(
is=>'rw',isa=>'HashRef',
默认值=>sub{{},
触发器=>sub{shift->_changed(1)}
) ;
子构建{
我的($self)=@;
$self->_已更改(0)#重置标志
监视%{$self->{value}},调试=>sub{
$self->\u已更改(1)
};
返回$self;
}
主包装;
我的$doc=Test::Document->new(值=>{a=>1,b=>{c=>3});
我的$x=$doc->value->{b}->{e};#不变
$doc->value->{b}->{e}=4;#改变
$doc->\u已更改(0);
删除$doc->value->{b}->{e};#改变
$doc->\u已更改(0);
$doc->value({a=>1});#改变
优点:有效:)
缺点:递归绑定方法在具有大量键和嵌套级别的哈希上可能会产生性能问题。我必须做一些基准测试
注意:我尝试使用magic vars,但是使用类似
sub()->{a}->{b}
语法的标量上下文传播会强制触发store
事件,即使没有(显式)赋值。欢迎您提出建议。如果您需要使用语法$self->attribute->{a}=?
来更新哈希键,我认为绑定哈希是唯一的(?)选项。但是,如果您可以将语法更改为$self->attribute()
,其中
可以是散列引用或标量,其中属性
现在是一个方法(而不是属性),并且旧的属性
重命名为,例如\u属性
,则可以避免使用绑定散列。现在,方法属性
将检查其参数是标量还是散列引用,并相应地更新\u属性
。@Håkon我绝对避免通过内部引用访问属性,但我正在开发一个类