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

时间:2015-04-01 10:38:23

标签: scala abstract-type type-members type-projection

我的情景如下:

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())

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

2 个答案:

答案 0 :(得分:3)

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

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

将其编译为一种方法是将createB的返回类型更改为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)
  }
}

答案 1 :(得分:1)

更新 给定this answer我不确定这是否应被视为错误

这是一个错误: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
  }
}

看起来像实施泄漏。有一种解决方法,涉及投射到交叉点类型(危险,铸造错误等;请参阅我的其他答案here

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!
  }
}
相关问题