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

13 浏览
0 Comments

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

我的场景如下:

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中,它报错了

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

这段代码有什么问题?如果可能的话,如何修正这段代码?

0
0 Comments

这是一个关于类型参数的抽象类型成员引用的问题。问题的原因是在使用具体类型作为参数时,编译器不能正确地推断出类型的成员,导致类型错误。这个问题被认为是Scala编译器的一个bug(SI-4377)。

解决这个问题的方法是使用类型转换到交集类型。下面是一个解决方法的示例代码:

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

这个解决方法需要使用`A.is`方法将类型参数转换为交集类型。然后可以在`bar`方法中正确地引用类型的成员。虽然这种方法可以解决问题,但是由于类型转换的不确定性,可能会导致其他问题,因此需要谨慎使用。

0
0 Comments

在上述内容中,出现了一个问题:在函数`foo`中,类型`B`实际上指的是`this.B`,而不是`D#B`(后者更为通用)。简单来说,`D#B`表示抽象类型`B`在任何`D`的实例中可以取到的任何可能类型,而`d.B`表示特定实例`d`中`B`的类型。

为了解决这个问题,有两种方法:

第一种方法是将`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)
  }
}

以上就是问题的原因以及解决方法。通过替换抽象类型为类型参数,可以避免类型不匹配的问题。

0