【问题标题】:Moose structured typesMoose 结构化类型
【发布时间】:2023-04-04 07:51:01
【问题描述】:

我想在 Moose 中创建一个结构化类型,它可以用作另一个 Moose 属性的类型。例如,我希望能够创建一个具有自己的 valueerror 属性的 name 属性。

因此,我想知道实现这一目标的最佳方法。我通过定义一个简单的 Moose 类来表示一个通用的 Field 对象,创建了一个工作示例。这具有valueerror 属性。然后我为Person 对象创建了另一个Moose 类。这有idname 属性,它们都是Field 类型:

定义一个通用字段对象:

package MyApp::Type::Field;
use Moose;
use namespace::autoclean;

has 'value' => ( is => 'rw' );  
has 'error' => ( is => 'rw', isa => 'Str' );

__PACKAGE__->meta->make_immutable;
1;

定义一个使用字段对象的 Person 对象:

package MyApp::Person;
use Moose;
use namespace::autoclean;
use MyApp::Type::Field;

has 'id'   => ( is => 'rw', isa => 'MyApp::Type::Field' );    
has 'name' => ( is => 'rw', isa => 'MyApp::Type::Field' );

__PACKAGE__->meta->make_immutable;
1;

对 Person 对象做一些事情:

package MyApp::Test;

use Moose;
use namespace::autoclean;
use MyApp::Person;

my $person = MyApp::Person->new();

# This works.
$person->id( MyApp::Type::Field->new() );
$person->id->value( 1 );
$person->id->error( 'Not found' );

# This fails as the name object has not yet been defined.
$person->name->value( 'Dave' );
# Can't call method "value" on an undefined value at ...

__PACKAGE__->meta->make_immutable;
1;

这可行,但在MyApp::Test 中,我希望能够直接访问该人的nameidvalueerror 属性,而无需先实例化一个新的MyApp::Type::Field 对象每个人的属性。

或者,换句话说,如果Person 类的用户不必这样做:$person->id( MyApp::Type::Field->new() ); 在能够使用id 属性之前,我更喜欢它。

有没有一种干净的方法可以实现这一目标?

【问题讨论】:

    标签: perl moose


    【解决方案1】:

    您不能简单地为属性提供default 吗?

    has 'id' => (
        is => 'rw',
        isa => 'MyApp::Type::Field',
        default => sub { MyApp::Type::Field->new }
    );
    

    ...或在BUILD 中执行等效操作。

    【讨论】:

    • 啊,是的,突然间它看起来如此明显。 :-) 感谢您的帮助。
    【解决方案2】:

    你也可以尝试强制:

    coerce 'MyApp::Type::Field'
        => from 'Int'
        => via  { MyApp::Type::Field->new( value => shift ) }
        ;
    

    只有这样:

    $person->id( 1 );
    

    设置它。尽管设置错误仍然需要按照您的方式进行。


    我可能应该提到您需要执行以下操作:

    • Moose::Util::TypeConstraints 添加到您放置coerce 的包中。
    • 在字段中添加coerce 标志:

      has id => ( is => 'rw', isa => 'MyApp::Type::Field', coerce => 1 );
      

    【讨论】:

    • 谢谢。实际上,我已经添加了来自 Str 和 HashRef 的强制,这使我能够像这样创建一个新的 Person:$person = MyApp::Person->new( id => { value => 1, error => 'Not found' }, name => { value => 'Dave' } );
    猜你喜欢
    • 2013-09-05
    • 1970-01-01
    • 1970-01-01
    • 2016-05-13
    • 1970-01-01
    • 2011-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多