Mooseを使用すると、属性がすでにを読み込まれなかった場合、ビルダーは、属性があるときに呼び出され、属性、上のlazy
builders
が最初にアクセスすることができます。属性の強制型変換はcoerce
で行うことができますが、属性がに設定されている場合は常にに適用されるため、オブジェクトの初期化時にも適用されます。レイジー属性強制は
遅延型変換を実装する方法を探していますが、属性は最初に読み込まれますが、最初にアクセスされたときにのみ強制されます。強制が高価な場合は、これが重要です。次の例では
、私はこれを行うには労働組合の種類と方法修飾子を使用します。
私は組合の種類を嫌い:
package My::Foo; use Moose; has x => ( is => 'rw', isa => 'ArrayRef | Int', required => 1 ); around "x" => sub { my $orig = shift; my $self = shift; my $val = $self->$orig(@_); unless(ref($val)) { # Do the cocerion $val = [ map { 1 } 1..$val ]; sleep(1); # in my case this is expensive } return $val; }; 1; my $foo = My::Foo->new(x => 4); is_deeply $foo->x, [ 1, 1, 1, 1 ], "x converted from int to array at call time";
しかしこれにはいくつかの問題があります + 方法修飾子アプローチ。 use coercion instead of unionsへの「ベストプラクティス」の提案に反する。宣言的ではありません。
私は多くクラス全体で多く属性でこれを行う必要があります。したがって、何らかのDRYが必要です。これは、メタ属性の役割、タイプ強制、何があります。
アップデート:私はオブジェクト内の高価な型変換をカプセル化し、このオブジェクトに外側強制を提供するために、ikegami'sの提案に従っ :
package My::ArrayFromInt;
use Moose;
use Moose::Util::TypeConstraints;
subtype 'My::ArrayFromInt::Inner',
as 'ArrayRef[Int]';
coerce 'My::ArrayFromInt::Inner',
from 'Int',
via { return [ (1) x $_ ] };
has uncoerced => (is => 'rw', isa => 'Any', required => 1);
has value => (
is => 'rw',
isa => 'My::ArrayFromInt::Inner',
builder => '_buildValue',
lazy => 1,
coerce => 1
);
sub _buildValue {
my ($self) = @_;
return $self->uncoerced;
}
1;
package My::Foo;
use Moose;
use Moose::Util::TypeConstraints;
subtype 'My::ArrayFromInt::Lazy' => as class_type('My::ArrayFromInt');
coerce 'My::ArrayFromInt::Lazy',
from 'Int',
via { My::ArrayFromInt->new(uncoerced => $_) };
has x => (
is => 'rw',
isa => 'My::ArrayFromInt::Lazy',
required => 1,
coerce => 1
);
1;
$foo->x->value
が呼び出された場合、これは動作します。しかし、私はMy::ArrayFromInt
と::Lazy
サブタイプを作成して、変換したい属性ごとにポイント2を解決するわけではありません。可能であれば$foo->x->value
に電話するのは避けたいと思います。
データを表す方法が2つある場合は、いずれかの表現を得ることができるはずです。オブジェクトを強制し、必要な形式でオブジェクトからデータを取得します。 [例](http://stackoverflow.com/questions/10506416/can-i-use-an-attribute-modifer-in-mose-in-a-base-class-to-handle-multiple-attri/10508753# 10508753) – ikegami
s/'map {1} 1 .. $ val' /'(1)x $ val'/ – ikegami
@ikegami問題は強制は高価だということです。私は属性が要求されている場合にのみ実行したい。 – devoid