scala - 抽象类型与类型参数

标签 scala type-parameter abstract-type

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

最佳答案

添加到我的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 中保持不变,
  • 在子类型中可以选择性地覆盖类型成员的方式 (而类型参数必须重新声明并传递给父类(super class)型)

  • (如 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/

    相关文章:

    java - 如何验证(泛型(generic argument))?

    scala - 通过最短路径链接隐式

    scala - akka http 使用 Json 支持和 xmlsupport

    java - 什么是 ScalaSignature?

    c# - 其中 t : multiple classes

    Scala 类型推断没有注意到这些类型是相同的,无论它们是什么

    scala - 在 Intellij 中运行 Scala 测试时出错

    scala - 为什么适当的类型 Any 和 Nothing 在类型不同时适合类型构造函数形状 F[_] ?

    scala - 在Scala 3中,如何替换已删除的通用类型投影?

    scala - 抽象类型+自身类型+类型覆盖,错误 "Value xxx is not a member of Component.this.T"