我试图让深刻的强制工作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'
]);
Run Code Online (Sandbox Code Playgroud)
当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 => $_) }) ],
);
Run Code Online (Sandbox Code Playgroud)
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($_))
Run Code Online (Sandbox Code Playgroud)
我知道我可以通过修改Family->new
使用BUILDARGS
sub 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";
Run Code Online (Sandbox Code Playgroud)
mom, dad, girl, dog
运行时打印得很好.
Moose/Moo/Mouse属性默认情况下不强制,因此即使类型约束具有强制,您也需要告诉属性使用该强制!
如果你使用的是Moose或Mouse,你可以这样做:
has members => (
is => 'ro',
isa => ArrayRef[ Object->plus_coercions(Str, q{ Person->new(name => $_) }) ],
coerce => 1,
);
Run Code Online (Sandbox Code Playgroud)
但是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,
);
Run Code Online (Sandbox Code Playgroud)