在什么情况下抽象类型应该优先于类型参数?
最佳答案
添加到我的previous answer on Abstract type vs. parameters ,您还有 JESSE EICHAR's recent blog post (2010 年 5 月 3 日)强调了一些关键差异:
trait C1[A] {
def get : A
def doit(a:A):A
}
trait C2 {
type A
def get : A
def doit(a:A):A
}
在
C2
在这种情况下,参数是“隐藏的”(作为内部抽象类型)。(除了,正如反义词所说,它实际上并没有被掩埋,见下文)
而对于泛型类型,参数被显式提及,帮助其他表达式知道它们应该使用什么类型
所以(C1:参数):
//compiles
def p(c:C1[Int]) = c.doit(c.get)
它可以编译,但您明确公开了 '
A
' 要使用的类型。和(C2:抽象类型):
// doesn't compile
def p2(c:C2) = c.doit(c.get)
<console>:6: error: illegal dependent method type
def p2(c:C2) = c.doit(c.get)
^
它无法编译,因为 '
A
' 在 p2 定义中从未提及,所以 doit
在编译类型时不知道它应该返回什么。当使用抽象类型并希望避免任何“类型泄漏”到接口(interface)(即希望公开“
A
”实际上是什么)时,您可以指定一个非常通用的类型作为 p2 的返回:// compiles because the internals of C2 does not leak out
def p(c:C2):Unit = c.doit(c.get)
或者您可以直接在
doit
中“修复”该类型。功能:def doit(a:A):Int
而不是 def doit(a:A):A
, 意思是:def p2(c:C2) = c.doit(c.get)
将编译(即使 p2 没有提及任何返回类型)最后( retronym 的评论)您可以指定
A
通过细化 C2 抽象参数显式地:scala> def p2(c:C2 { type A = Int }): Int = c.doit(c.get)
p2: (c: C2{type A = Int})Int
或者通过添加类型参数(并用它精炼 C2 抽象类型!)
scala> def p2[X](c:C2 { type A = X }): X = c.doit(c.get)
p2: [X](c: C2{type A = X})X
所以推荐抽象:
C2
(但要小心使用 C2
的函数定义)C2
的子类中以协变方式覆盖类型时 , 使用抽象类型(有界类型抽象)C2
的定义时通过特征类型 ,使用抽象类型(在将 A
与您的类(class)混合时,您不会有“C2
”来处理:您只混合 C2
)剩下的,简单的类型实例化 是需要,使用参数。
(如果您知道不需要扩展,但您仍然必须处理几种类型:这就是参数类型的用途)
retronym补充说:
主要区别 是
C2
只能在 A
中保持不变, (如 illustrating here :
trait T1 {
type t
val v: t
}
trait T2 extends T1 {
type t <: SomeType1
}
trait T3 extends T2 {
type t <: SomeType2 // where SomeType2 <: SomeType1
}
class C extends T3 {
type t = Concrete // where Concrete <: SomeType2
val v = new Concrete(...)
}
)
关于scala - 抽象类型与类型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3170821/