类型::微小和深刻的强制

时间:2014-04-10 07:40:00

标签: perl moo

我试图深入强制与Type::Tiny合作而没有任何成功。来自manual它说:

"某些参数化类型约束可以自动获取 如果他们的参数有强制,则强制执行。例如: 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元素实例化Str时,应自动将其强制转换为Person个对象。我已经尝试了一系列不同的想法(plus_coercions,类型库等)而没有任何运气。他们都以同样的方式失败。

使用plus_coercions(从StrObject

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中的BUILDARGS sub修改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

1 个答案:

答案 0 :(得分: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,
);