与Perl5中的大多数内容一样,有许多方法可以创建支持其属性的自定义类型强制的类.这是一个简单的,从数组引用到哈希:
#!/usr/bin/env perl package Local::Class { use Moo; use Types::Standard qw( HashRef ArrayRef ); has set => ( is => 'ro',coerce => 1,isa => HashRef->plus_coercions( ArrayRef,sub { return { map { $_ => 1} @{$_[0]} } },),); } my $o = Local::Class->new({ set => [qw( a b b c )] }); # $o->set now holds { a => 1,b => 1,c => 1}
我一直在尝试将这样的东西移植到Perl6,在我看来我需要的是一种将数组强制转换为SetHash的方法.到目前为止,我能够做到这一点的唯一方法是:
#!/usr/bin/env perl6 class Local::Class { has %.set; ## Wanted to have # has %.set is SetHash; ## but it dies with "Cannot modify an immutable SetHash" submethod TWEAK (:$set) { self.set = $set.SetHash; } } my $o = Local::Class.new( set => [< a b b c >] ); # $o.set now holds {:a,:b,:c}
解决方法
TWEAK在BUILD初始化对象之后运行,这就是提供奇数编号阵列会爆炸的地方.
将强制移动到BUILD时间,事情应按预期工作:
class Local::Class { has %.set; submethod BUILD (:$set) { %!set := $set.SetHash; } }
如果您可以将强制SetHash()参数类型与自动属性初始化结合使用会很好,但这会失败,因为sigil是属性名称的一部分,如果您想接受非参数,则参数不能为%-sigilled – 关联类型.
但是,如果您使用$-sigilled属性,它可以正常工作:
class Local::Class { has $.set; submethod BUILD (SetHash() :$!set) {} }
正如@smls指出的那样,以下变种
class Local::Class { has %.set is SetHash; submethod BUILD (:$set) { %!set = $set.SetHash; } }
可能应该工作,而不是死亡无法修改不可变的SetHash.
作为SetHash无法分配的解决方法,您可以使用
class Local::Class { has %.set is SetHash; submethod BUILD (:$set) { %!set{$set.SetHash.keys} = True xx *; } }