强制类型可以帮助您在例程中使用特定类型,但接受更广泛的输入.调用例程时,参数会自动转换为较窄的类型.
Run Code Online (Sandbox Code Playgroud)sub double(Int(Cool) $x) { 2 * $x } say double '21'; # 42 say double Any; # Type check failed in binding $x; expected 'Cool' but got 'Any'这里Int是强制参数的目标类型,而Cool是例程接受作为输入的类型.
但这个潜艇有什么意义呢?是不是$x只是一个Int?为什么要限制调用者Cool为参数实现?
我通过加倍的例子困惑,因为Int已经is Cool.所以我做了一个示例,其中类型不共享层次结构:
class Foo { method foomethod { say 'foomethod' } }
class Bar {}
class Quux is Foo {
# class Quux { # compile error
method Bar { Bar.new }
}
sub foo(Bar(Foo) $c) {
say $c.WHAT; # (Bar)
# $c.foomethod # fails if uncommented: Method 'foomethod' not found for invocant of class 'Bar'
}
foo(Quux.new)
Run Code Online (Sandbox Code Playgroud)
这里的invocant foo被限制为提供一个Foo可以转换为a Bar但foo甚至不能调用Fooon 的方法,$c因为它的类型是 Bar.那么为什么要foo关心那个被强制的类型Foo呢?
有人可以对此有所了解吗?还要感谢指向相应文档和规范部分的链接.我找不到任何有用的东西.
这样做是接受一个Cool的子类型的值,并尝试将其转换为Int.在这一点上它是一种诠释,不管它是什么了.
所以
sub double ( Int(Cool) $n ) { $n * 2 }
Run Code Online (Sandbox Code Playgroud)
真的可以被认为是(我认为这是它在Rakudo实际实现的方式)
# Int is a subtype of Cool otherwise it would be Any or Mu
proto sub double ( Cool $n ) {*}
# this has the interior parts that you write
multi sub double ( Int $n ) { $n * 2 }
# this is what the compiler writes for you
multi sub double ( Cool $n ) {
# calls the other multi since it is now an Int
samewith Int($n);
}
Run Code Online (Sandbox Code Playgroud)
因此,它接受Int,Str,Rat,FatRat,Num,Array,Hash等中的任何一个,并尝试在使用它之前将其转换为Int&infix:<*>,并且2.
say double ' 5 '; # 25
say double 2.5; # 4
say double [0,0,0]; # 6
say double { a => 0, b => 0 }; # 4
Run Code Online (Sandbox Code Playgroud)
您可以将其限制为Cool而不是Any,因为所有Cool值基本上都需要为Int提供强制.
(:( Int(Any) $ )可缩短为:( Int() $ ))
你可能会这样做的原因是你需要它Int在sub中,因为你正在调用其他代码来执行不同类型的不同操作.
sub example ( Int(Cool) $n ) returns Int {
other-multi( $n ) * $n;
}
multi sub other-multi ( Int $ ) { 10 }
multi sub other-multi ( Any $ ) { 1 }
say example 5; # 50
say example 4.5; # 40
Run Code Online (Sandbox Code Playgroud)
在这种特殊情况下,您可以将其写为其中之一
sub example ( Cool $n ) returns Int {
other-multi( Int($n) ) * Int($n);
}
sub example ( Cool $n ) returns Int {
my $temp = Int($n);
other-multi( $temp ) * $temp;
}
sub example ( Cool $n is copy ) returns Int {
$n = Int($n);
other-multi( $n ) * $n;
}
Run Code Online (Sandbox Code Playgroud)
它们都不像使用签名来强制它的那个一样清晰.
通常对于这样一个简单的功能,你可以使用其中一个,它可能会做你想要的.
my &double = * * 2; # WhateverCode
my &double = * × 2; # ditto
my &double = { $_ * 2 }; # bare block
my &double = { $^n * 2 }; # block with positional placeholder
my &double = -> $n { $n * 2 }; # pointy block
my &double = sub ( $n ) { $n * 2 } # anon sub
my &double = anon sub double ( $n ) { $n * 2 } # anon sub with name
my &double = &infix:<*>.assuming(*,2); # curried
my &double = &infix:<*>.assuming(2);
sub double ( $n ) { $n * 2 } # same as :( Any $n )
Run Code Online (Sandbox Code Playgroud)
更新今天回答了这个答案我得出结论我完全误解了@musiKk的所作所为.在@ darch的问题和@ musiKk的回答中最清楚地揭示了这一点:
@darch:或者你的问题是为什么人们可能更喜欢Int(酷)而不是Int(Any)?如果是这样的话,那就是要问的问题.
@musiKk:这正是我的问题.:)
回顾其他许多答案,我认为没有人按我现在认为的方式解决这个问题.
我当然可能是错的,所以我决定做的就是保留原来的问题,特别是保留标题,并保留原来的答案,而是写一个新的答案来解决@darch的重新制定问题.
Int $x我们可以声明:
sub double (Int $x) { ... } # Accept only Int. (No coercion.)
Run Code Online (Sandbox Code Playgroud)
然后这将工作:
double(42);
Run Code Online (Sandbox Code Playgroud)
但不幸的是打字42响应这个:
double(prompt('')); # `prompt` returns the string the user types
Run Code Online (Sandbox Code Playgroud)
导致double调用失败,Type check failed in binding $x; expected Int but got Str ("42")因为42虽然看起来像一个数字,但在技术上是一个类型的字符串Str,我们没有要求强制.
Int() $x我们可以在sub的签名中引入任意值的毯式强制:
sub double (Int(Any) $x) { ... } # Take Any value. Coerce to an Int.
Run Code Online (Sandbox Code Playgroud)
要么:
sub double (Int() $x) { ... } # Same -- `Int()` coerces from Any.
Run Code Online (Sandbox Code Playgroud)
现在,如果42在double(prompt(''));语句提示时键入,则运行时类型检查失败不再适用,而是运行时尝试将字符串强制转换为Int.如果用户键入格式正确的数字,则代码才有效.如果他们输入123abc强制,将在运行时失败,并显示一条错误消息:
Cannot convert string to number: trailing characters after number in '123?abc'
Run Code Online (Sandbox Code Playgroud)
任何值的毯式强制的一个问题是这样的代码:
class City { ... } # City has no Int coercion
my City $city;
double($city);
Run Code Online (Sandbox Code Playgroud)
在运行时失败并显示以下消息:"找不到'City'类调用的方法'Int'".
Int(Cool) $x我们可以选择任何价值的强制和全面强制之间的平衡点.
强制来自的最佳类通常是Cool类,因为保证Cool值可以很好地强制转换为其他基本类型或生成一个很好的错误消息:
# Accept argument of type Cool or a subclass and coerce to Int:
sub double (Int(Cool) $x) { ... }
Run Code Online (Sandbox Code Playgroud)
有了这个定义,以下内容:
double(42);
double(prompt(''));
Run Code Online (Sandbox Code Playgroud)
尽可能地工作,并且:
double($city);
Run Code Online (Sandbox Code Playgroud)
失败了"类型检查失败绑定$ x;预期酷但得到城市(城市)"这对于程序员而言可以说比"方法'Int'没有找到类'城市'的调用"更好一些.
为什么foo会首先关注那个被胁迫的类型是Foo?
希望现在显而易见的是,值得限制强制类型的唯一原因Foo是因为这是一种预期成功强制转换为Bar价值的类型(或者,也许是通过友好消息失败).
有人可以对此有所了解吗?还要感谢指向相应文档和规范部分的链接.我找不到任何有用的东西.
您最初引用的文档几乎都是针对最终用户文档的.希望它现在有意义,你已经准备好了.如果没有请评论,我们将从那里开始.
| 归档时间: |
|
| 查看次数: |
310 次 |
| 最近记录: |