Quick Tip #19: 创建可重用的数据类型
Perl 6 允许你使用类型来约束变量值,但是你不必拘泥于内置类型。一旦你定义了自己的类型,它们就表现得像内置类型一样。
下面是我从布拉德的 Subsets::Common模块偷得的一些子集(subsets):
my package EXPORT::DEFAULT {
...
subset Pos of Numeric where * > 0;
subset Neg of Numeric where * < 0;
subset Zero of Numeric where * == 0;
subset UNumeric of Numeric where * >= 0;
subset Even of Int where * % 2 == 0;
subset Odd of Int where * % 2;
subset Time::Hour12 of PosInt where * ~~ 1 .. 12;
subset Time::Hour24 of Int where * ~~ 0 .. 23;
subset Time::Minute of Int where * ~~ 0 .. 59;
subset Time::Second of Int where * ~~ 0 .. 59;
...
}
subset
关键字开启子集的声明, 后面跟着你想要的新类型的名字。这是一个子集,因为你基于已经存在的类型使用 of
关键字来声明该子集。在那之后,你可以使用一个 where
从句来改进你的新类型。
并且,布拉德把这些子集都放在了包里而且声明所有东西都是可导出的。
我也创建了一个 Perl 6 版本的 Chemistry::Elements。不要太在意代码中有什么东西, 多考虑你要声明的值是否满足你想要的约束。下面这个例子我声明了一个类型用来约束一个整数为一个已知的原子数:
subset ZInt of Cool is export where {
state ( $min, $max ) = %names.keys.sort( { $^a <=> $^b } ).[0,*-1];
( $_.truncate == $_ and $min <= $_ <= $max )
or
note "Expected a known atomic number between $min and $max, but got $_"
and
False;
};
对于我这个子集, 我通过把它声明为 is export
来导出它,以至于其它使用该模块的人能够从这个模块的外部使用这个类型。特别要注意的是,当给定的值不匹配时我可以指定一个特殊的错误提示信息。
文章下面还评论说:
“where * ~~ 0..59” is redundant; since it’s already being smart-matched, this can just be “where 0..59”.
意思是 where * ~~ 0..59
是多余的,因为它已经被智能匹配,它可以只写为 where 0..59
。