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 पर "सर्वोत्तम अभ्यास" सुझाव के खिलाफ चला जाता है। यह घोषणात्मक नहीं है।
मैं कई वर्गों में कई विशेषताओं के साथ ऐसा करने की जरूरत है। इसलिए डीआरवाई के कुछ रूपों की आवश्यकता है। यह मेटा-विशेषता भूमिकाएं, प्रकार-जबरन हो सकता है, आप क्या हैं।
अद्यतन: मैं 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
कहा जाता है। हालांकि यह बिंदु # 2 को हल नहीं करता है, क्योंकि मुझे प्रत्येक विशेषता के लिए My::ArrayFromInt
और ::Lazy
सबटाइप बनाने की आवश्यकता होगी, जिसे मैं बदलना चाहता हूं। और यदि संभव हो तो मैं $foo->x->value
पर कॉल करना से बचना चाहता हूं।
यदि डेटाम का प्रतिनिधित्व करने के दो तरीके हैं, तो कोई भी प्रतिनिधित्व प्राप्त करने में सक्षम होना चाहिए। किसी ऑब्जेक्ट में कॉरर्स करें, फिर उस ऑब्जेक्ट से डेटा को इच्छित प्रारूप में लाएं। [उदाहरण] (http://stackoverflow.com/questions/10506416/can-i-use-an-attribute-modifer-in-moose-in-a-base-class-to-handle-multiple-attri/10508753# 10508753) – ikegami
एस/'मानचित्र {1} 1 .. $ val' /' (1) x $ val'/ – ikegami
@ikegami समस्या यह है कि मजबूती महंगा है; मैं केवल यह करना चाहता हूं अगर विशेषता के लिए पूछा जा रहा है। – devoid