现在有:
has 'id' => (
is => 'rw',
isa => 'Str',
default => sub { "id" . int(rand(1000))+1 }
);
工作正常,:
PKG->new(id => 'some'); #the id is "some"
PKG->new() #the id is #id<random_number>
在下一个场景中:
my $value = undef;
PKG->new(id => $value);
(当然)有一个错误:
Attribute (id) does not pass the type constraint because: Validation failed for 'Str' with value undef at /Users/me/perl5/perlbrew/perls/perl-5.16.3/lib/site_perl/5.16.3/darwin-thread-multi-2level/Moose/Exception.pm line 37
问题是:
如何在设置为undef之后更改值(仅当它是$ undef时)?所以,
has 'id' => (
is => 'rw',
isa => 'Str|Undef', #added undef to acceptable Type
default => sub { "id" . int(rand(1000))+1 }
);
现在,它接受$undef
,但我不想要$undef
,但想要"id" . int(rand(1000))+1
。如何在设置之后更改属性值?
仅为不是构造函数的访问器调用after
。从coercion
到Undef
可能有些奇怪的Str
- 但这个属性只有 吗?
Ps:使用PKG->new( id => $value // int(rand(10000)) )
是不可接受的解决方案。模块应该接受$undef
并且应该静默地将其更改为随机数。
答案 0 :(得分:6)
Type::Tiny的目标之一是轻松将强制添加到个别属性中。这是一个例子:
use strict;
use warnings;
{
package Local::Test;
use Moose;
use Types::Standard qw( Str Undef );
my $_id_default = sub { "id" . int(rand(1000)+1) };
has id => (
is => 'rw',
isa => Str->plus_coercions(Undef, $_id_default),
default => $_id_default,
coerce => 1,
);
__PACKAGE__->meta->make_immutable;
}
print Local::Test->new(id => 'xyz123')->dump;
print Local::Test->new(id => undef)->dump;
print Local::Test->new->dump;
您还可以查看MooseX::UndefTolerant,它会将undef
值传递给构造函数,就好像它们被完全省略一样。这不会涵盖将undef传递给访问者;只是构造者。
答案 1 :(得分:2)
这是另一种选择,使用Moose'BRO构造方法,在创建对象后调用它。
#!/usr/bin/perl
package Test;
use Moose;
has 'id' => (
is => 'rw',
isa => 'Str|Undef',
);
sub BUILD {
my $self = shift;
unless($self->id){
$self->id("id" . (int(rand(1000))+1));
}
}
1;
package Main;
my $test = Test->new(id => undef);
print $test->id; ###Prints random number if id=> undef
有关BUILD的更多信息: http://metacpan.org/pod/Moose::Manual::Construction#BUILD
答案 2 :(得分:0)
@choroba在评论中提及triggers。基于此,找到了下一个解决方案。在id=>undef
的情况下,触发器被调用两次,否则它会起作用。
use Modern::Perl;
package My;
use namespace::sweep;
use Moose;
my $_id_default = sub { "id" . int(rand(100_000_000_000)+1) };
my $_check_id = sub { $_[0]->id(&$_id_default) unless $_[1] };
has id => (
is => 'rw',
isa => 'Str|Undef',
default => $_id_default,
trigger => $_check_id,
);
__PACKAGE__->meta->make_immutable;
package main;
say My->new->id;
say My->new(id=>'aaa')->id;
say My->new(id=>undef)->id;