问题 Int(酷)强制的重点是什么?
关于功能的Perl 6网站说
强制类型可以帮助您在例程中使用特定类型,但接受更广泛的输入。调用例程时,参数会自动转换为较窄的类型。
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)
在这里的呼吁 foo
被限制提供一个 Foo
可以转换为 Bar
但 foo
甚至不能称之为方法 Foo
上 $c
因为它的类型 是 Bar
。那么为什么呢 foo
关心被胁迫的类型是什么 Foo
首先?
有人会对此有所了解吗?此外,还赞赏指向相应文档和规范部分的链接。我找不到任何有用的东西。
4977
2018-01-19 10:47
起源
答案:
指定参数类型,没有强制: Int $x
我们可以声明:
sub double (Int $x) { ... } # Accept only Int. (No coercion.)
然后这将工作:
double(42);
但不幸的是打字 42
对此:
double(prompt('')); # `prompt` returns the string the user types
导致 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.
要么:
sub double (Int() $x) { ... } # Same -- `Int()` coerces from Any.
现在,如果你输入 42
当提示时 double(prompt(''));
语句,运行时类型检查失败不再适用,而是运行时尝试将字符串强制转换为Int。如果用户键入格式正确的数字,则代码才有效。如果他们打字 123abc
强制将在运行时失败,并显示一条错误消息:
Cannot convert string to number: trailing characters after number in '123abc'
任何值的毯式强制的一个问题是像这样的代码:
class City { ... } # City has no Int coercion
my City $city;
double($city);
在运行时失败并显示以下消息:“找不到'City'类调用的方法'Int'”。
使用Cool值强制指定参数类型: Int(Cool) $x
我们可以选择任何价值的强制和全面强制之间的平衡点。
强迫来自的最佳阶层往往是 Cool
class,因为Cool值可以保证很好地强制转换为其他基本类型或生成一个很好的错误消息:
# Accept argument of type Cool or a subclass and coerce to Int:
sub double (Int(Cool) $x) { ... }
有了这个定义,以下内容:
double(42);
double(prompt(''));
尽可能地工作,并且:
double($city);
失败的“类型检查失败绑定$ x;预期酷但得到城市(城市)”这对于程序员而言可以说比“方法'Int'找不到类'城''的调用更好一点。
为什么foo会首先关注那个被胁迫的类型是Foo?
希望现在显而易见的是,值得限制从类型到强制的唯一原因 Foo
是因为这是一种预期成功强迫的类型 Bar
价值(或者,也许是友好消息失败)。
有人会对此有所了解吗?此外,还赞赏指向相应文档和规范部分的链接。我找不到任何有用的东西。
您最初引用的文档几乎都是针对最终用户文档的。希望它现在有意义,你已经完成了。如果没有请评论,我们将从那里开始。
4
2018-01-20 02:38
这样做是接受一个子类型的值 凉,并试图将其转换为 诠释。那时候呢 是 一个 诠释 无论以前是什么。
所以
sub double ( Int(Cool) $n ) { $n * 2 }
真的可以被认为是(我认为这是它在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);
}
所以这接受任何 诠释, STR, 鼠, FatRat, 民, 排列, 哈希等等,并试图将其转换为 诠释 在打电话之前 &infix:<*>
用它,和 2
。
say double ' 5 '; # 25
say double 2.5; # 4
say double [0,0,0]; # 6
say double { a => 0, b => 0 }; # 4
您可以将其限制为a 凉 代替 任何 所有 凉 基本上需要价值来提供强制 诠释。
( :( 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
在这种特殊情况下,您可以将其写为其中之一
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;
}
它们都不像使用签名来强制它的那个一样清晰。
通常对于这样一个简单的功能,你可以使用其中一个,它可能会做你想要的。
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 )
4
2018-01-19 17:30
我错过了什么吗?我不是Perl 6专家,但似乎语法允许一个人独立指定 允许哪些输入类型 和 如何将输入呈现给函数。
限制允许的输入很有用,因为这意味着当使用无意义的参数调用函数时,代码将导致错误,而不是静默(无用)类型转换。
我不认为这两种类型不是分层关系的例子是有道理的。
2
2018-01-19 14:57
我相信答案很简单,你可能不想限制论证 Int
即使你将它视为 Int
在子内。说出于某种原因你希望能够将一个数组乘以一个哈希,但是如果args不能被视为哈希则会失败 Int
(即不是 Cool
)。
my @a = 1,2,3;
my %h = 'a' => 1, 'b' => 2;
say @a.Int; # 3 (List types coerced to the equivalent of .elems when treated as Int)
say %h.Int; # 2
sub m1(Int $x, Int $y) {return $x * $y}
say m1(3,2); # 6
say m1(@a,%h); # does not match
sub m2(Int(Cool) $x, Int(Cool) $y) {return $x * $y}
say m2('3',2); # 6
say m2(@a,%h); # 6
say m2('foo',2); # does not match
当然,您也可以在没有签名的情况下执行此操作,因为数学运算会自动强制类型:
sub m3($x,$y) {return $x * $y}
say m3(@a,%h); # 6
然而,这会将你的类型检查推迟到sub的内部,这会破坏签名的目的,并阻止你制作sub a multi
0
2018-01-20 15:02
所有亚型 Cool
将(正如酷要求他们)强迫他们 Int
。因此,如果您的子内部的操作员或例程仅适用于 Int
参数,您不必添加额外的语句/表达式转换为Int也不需要考虑其他子类型的操作符/例程的代码 Cool
。它强制论证将是一个 Int
无论你在哪里使用它都在你的子里面。
你的例子是倒退的:
class Foo { method foomethod { say 'foomethod' } }
class Bar {}
class Quux is Bar {
method Foo { Foo.new }
}
sub foo(Foo(Bar) $c) {
#= converts $c of type Bar to type Foo
#= returns result of foomethod
say $c.WHAT; #-> (Foo)
$c.foomethod #-> foomethod
}
foo(Quux.new)
0
2018-01-21 16:53