6

私たちのクラスには、計算された値を表す属性を作成するパターンがあります。明らかな理由から、計算された値をキャッシュし、基になる値の 1 つが変更されたときにキャッシュを無効にしたいと考えています。

したがって、現在これがあります:

package FooBar;
use Moose;

has 'foo' => (
        accessor => {
            'foo' => sub {
                my $self = shift;
                if (@_ > 0) {
                    # writer
                    $self->{foo} = $_[0];

      # reset fields that are dependant on me
      $self->{bar} = undef;
                }
                # reader part;
                return $self->{foo};
            }
        }
    );

has 'bar' => (
        accessor => {
            'bar' => sub {
                my $self = shift;
                if (@_ > 0) {
                    # writer
                    $self->{bar} = $_[0];
                }
                # reader part;
                $self->{bar} = calculate_bar($self->foo, $self->baz) 
                        if (not defined($self->{bar}));
                return $self->{bar};
            }
        }
    );

sub calculate_bar { ... }

計算された値が他の計算された値に依存する場合、この長時間の方法は非常に面倒でエラーが発生しやすくなります。

「バー」が依存する属性を監視するためのよりスマートでシンプルな方法と、「foo」が依存している人を知る方法はありますか? また、ハッシュメンバーアクセスを介してバーを設定しないようにするにはどうすればよいですか?

4

4 に答える 4

11

私があなたを正しく理解していれば、トリガーを使用して、属性が設定されているときに属性をクリアできます。次に例を示します。

has 'foo' => (
    is      => 'rw',
    trigger => sub{
        my ($self) = @_;
        $self->clear_bar;
    }
);

has 'bar' => (
    is      => 'rw',
    clearer => 'clear_bar',
    lazy    => 1,
    default => sub{
        my ($self) = @_;
        return calculate_bar( ... );
    }
);

したがって、foovia への書き込みはクリアされ、次のアクセスで再作成されます$obj->foo($newvalue)bar

于 2009-11-21T14:14:49.080 に答える
4

メモ化を明示的にしてプログラム全体をより透過的にすることができるのに、レイジーで属性の暗黙的なメモ化を使用することで、これを自分自身で難しくしている可能性は十分にあると思います

has [qw/foo bar baz/] => ( isa => 'Value', is => 'rw' );

use Memoize;
memoize('_memoize_this');

sub old_lazy_attr {
    my $self = shift;
    _memoize_this( $self->attr1, $self->attr2, $self->attr3 );
}

sub _memoize_this {
    my @args = @_;
    # complex stuff
    return $result
}

内部キャッシュの情報と制御については、 cpan のMemoizeを参照してください。Memoized 関数はオブジェクトの状態に依存できないことも覚えておいてください。したがって、引数は明示的に渡す必要があります

于 2009-11-21T20:20:39.387 に答える
0

Moose の内部構造とメタ オブジェクト プロトコルについてはまだ調べていませんが、良い機会だと思います。

コード生成にパッチを適用して、属性を次のように指定した場合

has 'foo' => ();
has 'bar' => ( 
    depends_on => [qw( foo )],
    lazy => \&calculate_bar,
);

コード生成フェーズでは、上で指定したようにfooおよびbar属性のコードを作成します。

これを行う方法は、読者に委ねられた演習です。手がかりがあれば、始めてみます。残念ながら、私がアドバイスできるのは「これは MOP の仕事です」ということだけです。

于 2009-11-23T01:21:25.620 に答える
0

これは機能しますか?

#!/usr/bin/perl

package Test;

use Modern::Perl;
use Moose;

has a => (is => 'rw', isa => 'Str', trigger => \&change_a);
has b => (is => 'rw', isa => 'Str', trigger => \&change_b);
has c => (is => 'rw', isa => 'Str');

sub change_a
{
    my $self = shift;
    say 'update b';
    $self->b($self->a . ', bar');
}   

sub change_b
{
    my $self = shift;
    say 'update c';
}   

package main;

my $test = Test->new->a('Foo');

出力:

$ perl test.pl
update b
update c
于 2009-11-21T14:14:53.183 に答える