在什么情况下抽象类型应优先于类型参数?抽象类型与类型参数
回答
要添加到我的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
不知道在编译类型什么是应该返回。
当使用抽象类型和希望避免任何“式泄漏”的界面(即想暴露什么“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
(但要谨慎使用功能的定义C2
) - 当您想在的子类中共同覆盖类型,使用抽象类(有限制类型抽象)
- 当你想通过特质这些
C2
类型的定义混合,使用抽象类(你会不会有“A
”对付混合C2
时类:你只混合C2
)
对于剩下的,在简单类型实例是需要,使用的参数。
(如果你知道,没有扩展将是必要的,但你仍然必须处理几种类型:那是什么参数类型是)
retronym补充说:
是主要区别
- 方差:
C2
只能是不变在A
, - 该类型的成员可在亚型(而类型参数必须被重新声明并传递到超类型)
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(...)
}
)被选择性地重写的方式
这不是真正的埋藏:'def p2(c:C2 {type A = Int}):Int = c.doit(c.get)'。或者:'def p2 [X](c:C2 {type A = X}):X = c.doit(c.get)'。主要区别是方差('C2'只能在'A'中不变),并且类型成员可以在子类型中有选择地覆盖,而类型参数必须重新声明并传递给超类型。 – retronym 2010-07-03 16:01:37
@retronym:*“主要区别是方差......以及类型成员可以被选择性覆盖的方式”*这是否意味着与其中一个可能相关的所有事情都可能与其他方式有关?除了你提到的两个方面。唯一的区别是语法? – Lii 2015-12-22 05:07:23
- 1. 与抽象类型交换类型参数
- 2. 抽象类型与类型参数 - 区别在哪里?
- 3. 类型参数化抽象类
- 4. Scala:类参数中的抽象类型
- 5. Kotlin抽象类与泛型参数和使用类型参数的方法
- 6. 抽象类型
- 7. 抽象类与类类型属性
- 8. scala抽象类型参数化`this.type`
- 9. Java抽象方法参数类型
- 10. 类型参数的约束:接口与抽象类
- 11. 参数类型可能不是指一个抽象类型
- 12. 抽象非类型模板参数的类型
- 13. 在scala中混合类型参数和抽象类型
- 14. 斯卡拉:使用类型参数或抽象类型,类型限制
- 15. 抽象数据类型
- 16. ML抽象数据类型
- 17. OCaml抽象类型函数
- 18. Understaing抽象类型
- 19. Java抽象类和类型
- 20. 抽象类 - 儿童类型
- 21. Haskell的类型类与参数类型
- 22. 抽象类型的Ada OOP“generic”类型
- 23. 使用虚拟类型(抽象类型)
- 24. 如何抽象类型类型?
- 25. 从抽象类和类型参数固有处理类
- 26. Haskell中的抽象数据类型与参数化多态性
- 27. 铸造Java对象泛型类型与已知类型参数
- 28. 模板参数与类型参数与非类型参数
- 29. 使用结构图替换泛型类型参数中的抽象类型
- 30. 参考抽象类型成员
是不是已经在http://stackoverflow.com/questions/1154571/scala-abstract-types-vs-generics/1154727#1154727? – VonC 2010-07-03 08:55:06
@VonC:我看到了答案,但并不满意。 – 2010-07-03 09:11:52
我试图在下面进行说明,然后从Jesse EICHAR发布最新博客文章。 – VonC 2010-07-03 09:16:44