2016-12-02 104 views
3

与Perl5中的大多数情况一样,创建支持其属性的自定义类型强制的类的方法很多。这里有一个简单的,从一个数组引用散列:Perl6类属性中的类型强制

#!/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,它似乎像什么,我需要的是强制的ArraySetHash方式。到目前为止,我已经能够做到这一点的唯一方法是这样的:

#!/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} 

但这似乎并没有对我而言,做正确的方式,至少是在微小的细节将奇数列表传递给构造函数会导致脚本死掉。

那么,这是如何在Perl6中完成的呢?推荐的方法是什么(因为我确定有不止一种方法)为类属性实现自定义类型强制?

回答

3

TWEAK在对象被初始化为BUILD后运行,这就是提供一个奇数数组会爆炸的地方。

移动胁迫BUILD时间,事情应该按预期工作:

class Local::Class { 
    has %.set; 
    submethod BUILD (:$set) { 
    %!set := $set.SetHash; 
    } 
} 

这将是很好,如果你可以在自动属性初始化组合使用强迫SetHash()参数类型,但是这也将失败sigil是属性名称的一部分,如果您想要接受非关联类型,则参数不能为% -igill。

class Local::Class { 
    has $.set; 
    submethod BUILD (SetHash() :$!set) {} 
} 

由于@smls指出,下面的变型

class Local::Class { 
    has %.set is SetHash; 
    submethod BUILD (:$set) { 
    %!set = $set.SetHash; 
    } 
} 

或许应该工作以及:

但是,如果改为使用$ -sigilled属性,它工作正常而不是与一起死亡不能修改不可变的SetHash

至于SetHash不是分配的一种解决方法,你可以使用

class Local::Class { 
    has %.set is SetHash; 
    submethod BUILD (:$set) { 
    %!set{$set.SetHash.keys} = True xx *; 
    } 
} 
+2

我认为它实际上应该一起工作'有%.SET是SetHash;'为好,而“无法修改不可改变的SetHash “只是一个Rakudo错误。 – smls

+1

@smls:同意; cf编辑 – Christoph

+1

'子方法BUILD(SetHash():$ set){%!set:= $ set}'也适用 –