引用类型参数的抽象类型成员

Referring abstract type member of a type parameter

我的场景是这样的:

trait A {
    type B
    def foo(b: B)
}

trait C[D <: A] {
    val d: D
    def createB(): D#B
    def bar() {
        d.foo(createB)
    }
}

在 REPL 中,它抱怨

<console>:24: error: type mismatch;
 found   : D#B
 required: C.this.d.B
       a.bar(createB())

这有什么问题吗?以及(如果可能的话)如何更正此代码?

D#B 是类型投影,与 d.B 不同。您有类型不匹配,因为在 foo 中,B 实际上意味着 this.B,这与 D#B 不同(后者更通用)。 非正式地,您可以将 D#B 视为表示抽象类型 B 可以为 D 的任何实例采用的任何可能类型,而 d.B 是 [=15] 的类型=] 对于特定实例 d.

有关某些上下文,请参阅 What does the `#` operator mean in Scala? and What is meant by Scala's path-dependent types?

编译它的一种方法是将 createB 的 return 类型更改为 d.B:

def createB(): d.B

但是在很多情况下,这样的解决方案限制太多,因为您被绑定到特定实例 d,这可能不是您想要的。 另一种解决方案是用类型参数替换抽象类型(尽管它更冗长):

trait A[B] {
  def foo(b: B)
}

trait C[B, D <: A[B]] {
  val d: D
  def createB(): B
  def bar() {
    d.foo(createB)
  }
}

更新 给定我不确定这是否应该被视为一个错误

这是一个错误:SI-4377。明确的类型归属产生

trait C[D <: A] {
  val d: D
  def createB(): D#B
  def bar() {
    (d:D).foo(createB) 
      // [error]  found   : D#B
      // [error]  required: _3.B where val _3: D
  }
}

这看起来像是实现泄漏。有一个解决方法涉及转换为交叉类型(危险,转换错误等;请参阅我的其他答案

trait A {
  type B
  def foo(b: B)
}
case object A {
  type is[A0 <: A] = A0 {
    type B = A0#B
  }
  def is[A0 <: A](a: A0): is[A0] = a.asInstanceOf[is[A0]]
}

trait C[D <: A] {
  val d: D
  def createB(): D#B
  def bar() {
    A.is(d).foo(createB) // use it here!
  }
}