这是Perl 6中报告的错误:X::AdHoc instead of X::TypeCheck::Binding with subset parameter,于2015年11月首次报道 .
在玩我的Perl 6模块Chemisty::Elements时,我遇到了一个我没想到的Exception问题 .
我定义了一个类型 ZInt
,它将数字限制在周期图表上找到的序数(我在这里伪造了一点) . 然后我使用该类型将参数约束到子例程 . 我希望得到某种X::TypeCheck,但我得到X::AdHoc代替:
use v6;
subset ZInt of Cool is export where {
state ( $min, $max ) = <1 120>;
( $_.truncate == $_ and $min <= $_ <= $max )
or warn "Z must be between a positive whole number from $min to $max. Got <$_>."
};
sub foo ( ZInt $Z ) { say $Z }
try {
CATCH {
default { .^name.say }
}
foo( 156 );
}
首先,我得到两次警告,这很奇怪:
Z必须介于1到120之间的正整数之间 . <156> . 在zint.p6第5行的块中,Z必须在从1到120的正整数之间 . 得到<156> . 在块zint.p6第5行X :: AdHoc
但是,当我宁愿人们知道这是一个类型错误时,我得到 X::AdHoc
类型 .
我检查了没有 warn
会发生什么,并再次得到 X::AdHoc
:
subset ZInt of Cool is export where {
state ( $min, $max ) = <1 120>;
( $_.truncate == $_ and $min <= $_ <= $max )
};
所以,我想我可以抛出自己的异常:
subset ZInt of Cool is export where {
state ( $min, $max ) = <1 120>;
( $_.truncate == $_ and $min <= $_ <= $max )
or X::TypeCheck.new.throw;
};
但是,我得到一个警告:
在字符串上下文中使用类型为Any的未初始化值 . ^ name,.perl,.gist或.say可以根据需要对未定义的内容进行字符串化 .
在这一点上,我不抱怨 . 我认为其中一种方法需要我在文档中看到 new
或 throw
的参数 .
如何在没有警告的情况下获得我想要的类型以及我的自定义文本?
2 回答
不要抛出异常或与之发出警告 . 相反,你想失败:
我相信这是你的意图 . 没有你自己的异常也没关系,但是X :: TypeCheck中有一个bug . 它应该要么“操作”要么提供合理的默认,就像它“得到”和“预期”一样 .
您可以通过
--ll-exception
并尝试弄清楚您最终得到的错误和消息,但我不确定它会有多大帮助 .关于使用未初始化值的警告:您需要为
X::TypeCheck.new
提供一个名为operation
的参数;您可能提供的其他参数是got
和expected
,cf core/Exception.pm .然而,从子集声明中抛出是一个坏主意,因为针对该特定类型的任何智能匹配现在都会爆炸 . 稍微好一点的想法是
.fail
异常,但这对我来说仍然不合适:不是子集类型的成员不是一个例外情况 .或者,您可以提供一个完成死亡的多候选人:
如果您提供像
"hello"
这样的参数在数字转换时失败仍然会出现问题,因为%%
将抛出而不是传播失败,这可能被认为是Rakudo核心设置的缺陷 .你可以通过类似的东西解决这个问题
要么
参数类型检查,子集或where子句,失败和异常的整个交互可能有点脆弱,因此您可能需要进行一些实验,直到达到您喜欢的语义和行为 .
另一种方法是从
Cool
到Int
进行强制执行,并进行单独的范围检查:在一个理想的世界中,应该有一些方法来表达这种强制类型约束,如
ZInt(Cool)
.