问题描述
此处的hash2属性取决于hash1。实际上,hash2由hash1驱动。例如,
hash1-> key1 => value1,key2 => value2等。
hash2-> key1 => 6,key2 => 6等。它是长度(从hash1到哈希2的值)。
尝试了以下类似方法,但没有帮助。
has 'hash1' => (
is => 'rw',isa => 'HashRef[Str]',default => sub { {} },handles => {
map { $_ . '_hash1' => $_ } @hash_delegations
},);
has 'hash2' => (
is => 'rw',isa => 'HashRef',builder => '_filter_hash1',handles => {
map { $_ . 'hash2' => $_ } @hash_delegations
},);
sub _filter_hash1 {
my $self = shift;
for my $alias ($self->keys_hash1()) {
return {$alias,length($alias)};
}
}
Hash1将随着时间的过去而设置,不确定如何确保应如何捕获hash1上的事件以更新hash2中的条目。知道我该如何实现吗?
解决方法
您是否要创建值长度缓存?实际上,length如此之快,您无需对其进行缓存,但这可能只是更复杂的例子的简化示例。我会使用 trigger ,在第一个哈希上加上一个特征来强制通过方法设置值。直接更改哈希值不会触发其他属性的更改。
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
{ package My::Object;
use Moose;
my @hash_delegations = qw( keys );
has 'hash1' => (
is => 'rw',isa => 'HashRef[Str]',default => sub { {} },trigger => \&_update_hash2,traits => ['Hash'],handles => { set_hash1 => 'set' },);
has 'hash2' => (
is => 'ro',writer => '_set_hash2',isa => 'HashRef',);
sub _update_hash2 {
my ($self,$new,$old) = @_;
$self->_set_hash2({ map { $_ => length $self->hash1->{$_} }
keys %{ $self->hash1 }});
}
}
my $o = 'My::Object'->new(hash1 => {a => 42,b => 'Universe'});
say $o->hash2->{$_} for qw( a b );
$o->set_hash1(c => '0123456789');
say $o->hash2->{c};
$o->hash1->{c} = ""; # Wrong!
say $o->hash2->{c}; # Didn't change :-(
,
这是一个使用带有触发器和方法修饰符的只读散列的示例...
package MyApp;
use Z qw( Dumper );
use Hash::Util qw( unlock_ref_keys lock_ref_keys );
class '::My::Object' => sub {
my %common = (
is => 'rw',isa => HashRef[Str],trigger => sub { lock_ref_keys($_[1]) },default => sub { lock_ref_keys(my $ref = {}); $ref },handles_via => 'Hash',);
has hash1 => (
%common,handles => [
'set_hash1' => 'set','get_hash1' => 'get',],);
has hash2 => (
%common,isa => HashRef[Int],handles => [
'set_hash2' => 'set','get_hash2' => 'get',);
around set_hash1 => sub {
my ( $next,$self,$key,$val ) = ( shift,shift,@_ );
unlock_ref_keys( $self->hash1 );
unlock_ref_keys( $self->hash2 );
my $r = $self->$next( @_ );
$self->set_hash2( $key,length($val) );
lock_ref_keys( $self->hash1 );
lock_ref_keys( $self->hash2 );
return $r;
};
method BUILD => sub {
my ( $self,$args ) = @_;
if ( my $h1 = $args->{hash1} ) {
$self->set_hash1( $_,length $h1->{$_} ) for keys %$h1;
}
};
};
my $obj = 'My::Object'->new(
hash1 => { foo => 'xyzzy' },);
$obj->set_hash1('bar','quux');
print Dumper($obj);