#perl #moose
#perl #moose
Вопрос:
Здесь атрибут hash2 зависит от hash1. фактически, hash2 управляется hash1. например,
hash1 -> key1 => value1, key2 => value2 и т.д..
hash2 -> key1 => 6, key2 => 6 и т.д. это длина (значение из hash1, переходящее в hash2)
Пробовал что-то вроде приведенного ниже, но не помогло.
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. Есть идеи, как я могу этого добиться?
Ответ №1:
Вы пытаетесь создать кэш длин значений? На практике длина настолько быстра, что вам не нужно ее кэшировать, но это может быть просто упрощенный пример чего-то более сложного. Я бы использовал триггер плюс признак для первого хэша, чтобы принудительно установить значение с помощью метода. Прямое изменение значения хэша не приведет к изменению другого атрибута.
#!/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 => amp;_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 :-(
Ответ №2:
Вот пример, в котором используются хэши только для чтения с триггерами и модификаторами методов…
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);