从ArrayRef [HashRef]强制ArrayRef [MyClass] [英] Coercing ArrayRef[MyClass] from ArrayRef[HashRef]

查看:121
本文介绍了从ArrayRef [HashRef]强制ArrayRef [MyClass]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在尝试回答如何从大哈希值实例化Moose类时,我想我碰到了另一个地方不完全了解Moose类型的强制.由于某些原因,以下代码会发出警告:

In trying to answer How to instantiate Moose classes from a big hash, I think I have hit another place where I don't fully understand Moose type coercions. For some reason, the below code issues warnings:

You cannot coerce an attribute (departments) unless its type (ArrayRef[Company::Department]) has a coercion at ./test.pl line 12.
You cannot coerce an attribute (employees) unless its type (ArrayRef[Company::Person]) has a coercion at ./test.pl line 23.

但随后成功.

#!/usr/bin/env perl

use warnings;
use strict;

package Company;
use Moose;
use Moose::Util::TypeConstraints;

has 'id'   => (is => 'ro', isa => 'Num');
has 'name' => (is => 'ro', isa => 'Str');
has 'departments' => (is => 'ro', isa => 'ArrayRef[Company::Department]', coerce => 1);

coerce 'ArrayRef[Company::Department]',
  from 'ArrayRef[HashRef]',
  via { [ map { Company::Department->new($_) } @$_ ] };

package Company::Department;
use Moose;

has 'id'   => (is => 'ro', isa => 'Num');
has 'name' => (is => 'ro', isa => 'Str');
has 'employees' => (is => 'ro', isa => 'ArrayRef[Company::Person]', coerce => 1);

package Company::Person;
use Moose;
use Moose::Util::TypeConstraints;

has 'id'         => (is => 'ro', isa => 'Num');
has 'name'  => (is => 'ro', isa => 'Str');
has 'age'        => (is => 'ro', isa => 'Num');

coerce 'ArrayRef[Company::Person]',
  from 'ArrayRef[HashRef]',
  via { [ map { Company::Person->new($_) } @$_ ] };

package main;

my %hash = (
    company => {
        id => 1,
        name => 'CorpInc',
        departments => [
            {
                id => 1,
                name => 'Sales',
                employees => [
                    {
                        id => 1,
                        name => 'John Smith',
                        age => '30',
                    },
                ],
            },
            {
                id => 2,
                name => 'IT',
                employees => [
                    {
                        id => 2,
                        name => 'Lucy Jones',
                        age => '28',
                    },
                    {
                        id => 3,
                        name => 'Miguel Cerveza',
                        age => '25',
                    },
                ],
            },
        ],
    }
);

my $company = Company->new($hash{company});
use Data::Dumper;
print Dumper $company;

这应该怎么做? P.S.我只是尝试做

How should this have been done? P.S. I tried simply doing

coerce 'Company::Department',
  from 'HashRef',
  via { Company::Department->new($_) };

但是它可怕地死了.

推荐答案

好吧,它并不能完全成功,当您尝试使用coerce => 1更新这些字段时,您应该会感觉到.这是为什么:

Well, it doesn't succeed completely, and you should feel it when you'll try to update these fields with coerce => 1. That's why:

除非属性的类型约束包含以下内容,否则您不能传递强制=> 1 胁迫

You cannot pass coerce => 1 unless the attribute's type constraint has a coercion

以前,这已被接受,并且确实可行, 除了如果您尝试在对象被设置之后设置属性 创建后,将出现运行时错误. 现在,当您尝试定义属性时,您将得到一个错误.

Previously, this was accepted, and it sort of worked, except that if you attempted to set the attribute after the object was created, you would get a runtime error. Now you will get an error when you attempt to define the attribute.

还是,我想我找到了解决它的方法,首先引入子类型,然后改变包的顺序,其次:

Still, I think I find the way to fix it, by introducing subtypes, first, and changing the order of packages, second:

package Company::Person;
use Moose;
use Moose::Util::TypeConstraints;

subtype 'ArrayRefCompanyPersons',
  as 'ArrayRef[Company::Person]';

coerce 'ArrayRefCompanyPersons',
  from 'ArrayRef[HashRef]',
  via { [ map { Company::Person->new($_) } @$_ ] };

has 'id'         => (is => 'ro', isa => 'Num');
has 'name'  => (is => 'ro', isa => 'Str');
has 'age'        => (is => 'ro', isa => 'Num');

package Company::Department;
use Moose;

has 'id'   => (is => 'ro', isa => 'Num');
has 'name' => (is => 'ro', isa => 'Str');
has 'employees' => (is => 'ro', isa => 'ArrayRefCompanyPersons', coerce => 1);

package Company;
use Moose;
use Moose::Util::TypeConstraints;

subtype 'ArrayRefCompanyDepartments',
  as 'ArrayRef[Company::Department]';

coerce 'ArrayRefCompanyDepartments',
  from 'ArrayRef[HashRef]',
  via { [ map { Company::Department->new($_) } @$_ ] };

has 'id'   => (is => 'ro', isa => 'Num');
has 'name' => (is => 'ro', isa => 'Str');
has 'departments' => (is => 'ro', isa => 'ArrayRefCompanyDepartments', coerce => 1);

其余代码与您的版本相同.这项工作没有任何警告,而且表现得差不多(我想).

The rest of the code is the same as in your version. This works without any warnings, and more-o-less behaves like (again, I think) it should be.

这篇关于从ArrayRef [HashRef]强制ArrayRef [MyClass]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆