Moose ile, nitelik hala nüfuslu olmasaydı oluşturucu niteliktir çağrılan nitelikler üzerinde lazy
builders
ilk erişilen olabilir. coerce
ile bir öznitelik türü baskısına sahip olabilirsiniz, ancak bu özellik, özniteliğinde ayarlandığında, uygulanır;Tembel Özellik Zorlama
lazy coercion, bir özniteliğin başlangıçta yerleştirilebildiği, ancak yalnızca ilk erişildiğinde zorlanabileceği bir yöntem arıyorum. Bu zorlama pahalı olduğunda önemlidir.
Aşağıdaki örnekte, bunu yapmak için bir birlik tipi ve yöntemi düzenleyiciler kullanın:
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";
Ancak bu ile birkaç sorun vardır:
- Ben sendika türünü sevmediğim + yöntem değiştirici yaklaşım. use coercion instead of unions "En İyi Uygulamalar" önerisine aykırıdır. Bu beyan değil.
Ben birçok sınıflar arasında birçok özelliklere sahip yapmanız gerekir. Bu nedenle, bir miktar DRY gereklidir. Bu meta-özellik rolleri, tip-zorlama, neyin var?
Güncelleme: Bir nesnenin içindeki pahalı tip zorlama saklanması ve bu nesneye bir dış zorlama sağlamak ikegami's öneriyi takip :
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
denir, bu çalışır. Ancak bu, # 2 noktasını çözmez, çünkü dönüştürmek istediğim her özellik için My::ArrayFromInt
ve ::Lazy
alt türünü oluşturmam gerekir. Mümkünse $foo->x->value
'u aramaktan kaçınmak istiyorum.
Bir referans noktasını temsil etmenin iki yolu varsa, biri ya temsilleri alabilmelidir. Bir nesneyi zorlayın, ardından verileri istediğiniz formatta getirin. [Örnek] (http://stackoverflow.com/questions/10506416/can-i-use-an-attribute-modifer-in-moose-in-a-base-class-to-handle-multiple-attri/10508753# 10508753) – ikegami
s/'map {1} 1 .. $ val' /' (1) x $ val'/ – ikegami
@ikegami Sorun, zorlamanın pahalı olduğu; Sadece özellik isteniyorsa onu gerçekleştirmek istiyorum. – devoid