Perl6 class 属性中的类型强制
Type coercion in Perl6 class attribute
像 Perl5 中的大多数东西一样,有很多方法可以创建 class 支持其属性的自定义类型强制转换。这是一个简单的例子,从数组引用到散列:
#!/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,似乎我需要的是一种将 Array
强制转换为 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}
但在我看来,这并不是正确的做法,至少对于将奇数列表传递给构造函数这一微小细节而言,脚本会死掉。
那么,这在 Perl6 中是如何完成的?为 class 属性实施自定义类型强制转换的推荐方法是什么(因为我确定不止一种)?
TWEAK
在对象被 BUILD
初始化后运行,这就是提供奇数数组的地方。
将强制转换到 BUILD
时间,事情应该会按预期进行:
class Local::Class {
has %.set;
submethod BUILD (:$set) {
%!set := $set.SetHash;
}
}
如果您可以使用强制 SetHash()
参数类型与自动属性初始化相结合,那就太好了,但这会失败,因为印记是属性名称的一部分,并且参数不能是 %
-如果您想接受非关联类型,请签名。
但是,如果您改用 $
-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 *;
}
}
像 Perl5 中的大多数东西一样,有很多方法可以创建 class 支持其属性的自定义类型强制转换。这是一个简单的例子,从数组引用到散列:
#!/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,似乎我需要的是一种将 Array
强制转换为 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}
但在我看来,这并不是正确的做法,至少对于将奇数列表传递给构造函数这一微小细节而言,脚本会死掉。
那么,这在 Perl6 中是如何完成的?为 class 属性实施自定义类型强制转换的推荐方法是什么(因为我确定不止一种)?
TWEAK
在对象被 BUILD
初始化后运行,这就是提供奇数数组的地方。
将强制转换到 BUILD
时间,事情应该会按预期进行:
class Local::Class {
has %.set;
submethod BUILD (:$set) {
%!set := $set.SetHash;
}
}
如果您可以使用强制 SetHash()
参数类型与自动属性初始化相结合,那就太好了,但这会失败,因为印记是属性名称的一部分,并且参数不能是 %
-如果您想接受非关联类型,请签名。
但是,如果您改用 $
-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 *;
}
}