抽象类型与类型参数

时间:2010-07-03 08:24:00

标签: scala type-parameter abstract-type

在什么情况下,抽象类型应该优先于类型参数?

1 个答案:

答案 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中保持不变,
  • 可以在子类型中有选择地覆盖类型成员的方式(而类型参数必须重新声明并传递给超类型)

(如illustrating here

C2