10

我试图让深层强制工作Type::Tiny没有任何成功。从手册上说:

“某些参数化类型约束如果它们的参数有强制,则可以自动获取强制。例如: ArrayRef[Int->plus_coercions(Num, q{int($_)}) ] ......按照你的意思!”

我试图完成的是得到这样的“做我的意思”:

package Person;
use Types::Standard -types;
use Moo;

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

package Family;
use Types::Standard -types;
use Moo;

has members => (is => 'ro', isa => ArrayRef[InstanceOf['Person']]);

package main;

my $family = Family->new(members => [
  'mom',
  Person->new(name => 'dad'),
  Person->new(name => 'girl'),
  'dog'
]);

Family当使用 a 的元素进行实例化时,Str它们应该被自动强制转换为Person对象。我尝试了一系列不同的想法(plus_coercions、类型库等),但没有任何运气。他们都以同样的方式失败。

当使用 plus_coercions (from Strto Object)

package Family;

has members => (
  is => 'ro',
  isa => ArrayRef[ Object->plus_coercions(Str, q{ Person->new(name => $_) }) ],
);

Type::Tiny 抛出异常:

Reference ["mom",bless( {"name" => "dad"}, 'Person' ),bless( {"name" =...] did not pass type constraint "ArrayRef[Object]" (in $args->{"members"})
"ArrayRef[Object]" constrains each value in the array with "Object"
"Object" is a subtype of "Object"
"Object" is a subtype of "Ref"
Value "mom" did not pass type constraint "Ref" (in $args->{"members"}->[0])
"Ref" is defined as: (!!ref($_))

我知道我可以通过将参数修改为Family->new使用BUILDARGSsub in来解决这个问题Family,但如果 Type::Tiny 可以自动做到这一点,那就太好了。

更新

感谢 Tobys 的友好帮助,我得到了这个工作。唯一让我有点困扰的部分是使用ArrayRef[Object]而不是正确的ArrayRef[InstanceOf['Person']]InstanceOf没有任何plus_coercions)。任何Object类的实例都可以插入到中,这肯定不是您想要的。members

通过制作一个class_type. 这是完整的工作代码:

package Person;
use Types::Standard -types;
use Moo;

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

package Family;
use Types::Standard -types;
use Type::Utils -all;
use Moo;

my $Person = class_type { class => 'Person' };

my $Members = ArrayRef[
  $Person->plus_coercions(Str, q{ Person->new(name => $_) })
];

has members => (
  is     => 'ro',
  isa    => $Members,
  coerce => $Members->coercion,
);

sub list { join(', ', map { $_->name } @{ $_[0]->members }) }

package main;

my $family = Family->new(members => [
  'mom',
  Person->new(name => 'dad'),
  Person->new(name => 'girl'),
  'dog'
]);

print $family->list, "\n";

运行时打印效果很好mom, dad, girl, dog

4

1 回答 1

5

Moose/Moo/Mouse 属性默认不强制,所以即使类型约束强制,你也需要告诉属性使用强制!

如果你使用 Moose 或 Mouse,你可以这样做:

has members => (
  is     => 'ro',
  isa    => ArrayRef[ Object->plus_coercions(Str, q{ Person->new(name => $_) }) ],
  coerce => 1,
);

但是 Moo 不支持coerce=>1;相反,它期望一个 coderef 或重载的对象充当强制。Type::Tiny 可以通过调用为你提供合适的重载对象$type->coercion

# Let's store the type constraint in a variable to avoid repetition...
my $type = ArrayRef[
  Object->plus_coercions(  Str, q{Person->new(name => $_)}  )
];

has members => (
  is     => 'ro',
  isa    => $type,
  coerce => $type->coercion,
);
于 2014-04-10T18:24:15.030 回答