在什么情况下,抽象类型应该优先于类型参数?
答案 0 :(得分:18)
要添加到我的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)
^
它没有编译,因为在p2定义中从未提及过'A
',所以doit
在编译类型时不知道它应该返回什么。
当使用抽象类型和想要避免任何“类型泄漏”到接口时(即想要公开'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的评论)您可以通过改进C2抽象参数明确指定A
:
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
中的抽象类型(但要警惕使用{{1的函数的定义) }})C2
的子类中重复覆盖类型,请使用抽象类型(带有有界类型的抽象)C2
类型的定义,请使用抽象类型(混合时不会有'C2
'来处理{ {1}}与您的班级:您只混合A
)对于其他需要简单类型实例化的部分,请使用参数 (如果你知道不需要扩展,但你仍然需要处理几种类型:这就是参数类型的用途)
retronym补充道:
主要差异是
C2
只能在C2
中保持不变,C2
)