在Perl 6中,您可以指定可以强制类型的类型.如果你需要一个Int但可以转换为其他的东西Int.当您不希望单独的候选项Int和Str字符串表示整数值时,这很方便.
但是,似乎转换有点激进,因为转换不仅改变了类型,而且愿意改变数据.这部分是改变类型的混淆和将数字截断为整数的预期操作的问题.从概念上讲,这些是不同的想法,但它们交织在一起Str.Int(实际上是将一次旅行夹在中间Numeric):
sub foo ( Int:D() $n ) { put "Got <$n> of type {$n.^name}" }
foo( 80 ); # Got <80> of type Int
foo( '99' ); # Got <99> of type Int
foo( 1.5 ); # Got <1> of type Int
foo( '1.5' ); # Got <1> of type Int
Run Code Online (Sandbox Code Playgroud)
试图限制这Str一点并不是更好:
sub foo ( Int:D(Str:D) $n ) { put "Got <$n> of type {$n.^name}" }
foo( '1.5' ); # Got <1> of type Int
Run Code Online (Sandbox Code Playgroud)
我可以制作一些似乎最容易理解的适配器:
multi foo ( Int:D $n ) {
put "Got <$n> of type {$n.^name}"
}
multi foo ( Str:D $n where { $^n.Int == $^n.Numeric } ) {
foo( $n.Int );
}
foo( '1.5' ); # Cannot resolve ...
Run Code Online (Sandbox Code Playgroud)
我可能会想出一些子集,但这并不令人满意.所以诀窍是,我可以在不改变价值的情况下强制这样做(即使它改变了表示)吗?
事实证明,此功能已损坏且没有修复时间表:RT 132980.基本上,不强制执行目标类型.文档已更新.我的建议是根本不使用它.
一个可能的签名是
Numeric() $ where Int
Run Code Online (Sandbox Code Playgroud)
或者,限制为字符串,
Numeric(Str:D) $ where Int
Run Code Online (Sandbox Code Playgroud)
Int:D(Any)在Rakudo中的工作方式是创建一个接受的多候选者Any,将其转换为Int,并使用结果调用原始子例程.
如果您自己这样做,您可以更好地控制它的工作方式.
proto sub foo ( Int:D() $n ) {*}
multi sub foo ( Any:D $n ) {
my $i = try $n.Numeric.narrow;
if $i ~~ Int:D {
samewith $i
} else {
X::TypeCheck::Binding::Parameter.new(
# there are more arguments that should be added here
got => $n,
expected => Int:D(),
).throw
}
}
multi sub foo ( Int:D $n ) { put "Got <$n> of type {$n.^name}" }
Run Code Online (Sandbox Code Playgroud)