我试图深入强制与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(从Str
到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
中的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
。
答案 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,
);