【问题标题】:Moose how to change the attribute value only when it is $undef?Moose如何仅在$undef时更改属性值?
【发布时间】:2014-03-17 21:59:25
【问题描述】:

现在有:

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 只为访问器调用,而不是为构造器调用。也许从UndefStr 的一些奇怪的coercion - 但 用于这一属性?

Ps:使用PKG-&gt;new( id =&gt; $value // int(rand(10000)) ) 不是一个可接受的解决方案。模块应该接受$undef,并且应该默默地将其更改为随机数。

【问题讨论】:

标签: perl moose


【解决方案1】:

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 传递给访问器;只是构造函数。

【讨论】:

  • Tiny 模块的 LOT 文档 :) - 但它似乎是许多事情的伟大模块......需要 RTFM,但为此 - 它有效. :) 谢谢。
【解决方案2】:

这里有一个替代方法,使用 Moose 的 BUILD 方法,该方法在对象创建后调用。

#!/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

【讨论】:

  • 不错!无需任何外部模块。谢谢! :)
【解决方案3】:

@choroba 在评论中提到了triggers。基于此,找到了下一个解决方案。在id=&gt;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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    • 2017-12-26
    相关资源
    最近更新 更多