因此,这就是我不断使用Scala遇到各种情况的问题-即使情况明确,它似乎也忽略了隐式类型。我承认这可能是我的理解,但是在强调占位符时,我总是遇到麻烦。例如,下面的例子(为了证明这一点是虚构的)。特征X的第二个位置必须是某种

object TestRun extends App {

  trait X[T, Y<:X[_,_]] {
    def doesX:Unit
    def providesY:Y
  }

  class Test extends X[Int,Test]{
    override def doesX: Unit = println("etc..")
    def providesY:Test =  new Test
  }

  val a:X[_,_] = new Test //yes I know I could define a better here, its just to demo. I shouldn't have to explicitly relabel the 2nd _ as _<:X[_,<:X[ etc..
  val b = a.providesY //clearly this has to be at least a (something) WITH X, but scala claims this as "Any"

  b.doesX //error won't compile!!

  //trait

}

最佳答案

当你写:

val a: X[_, _] = new Test
            ^
      //  This is treated as if the type parameter is Any, for the most part


您正在告诉编译器aX,在这里您无需关心其类型参数是什么。也就是说,假定无界通配符_的上限是Any,仅此而已。

providesY使用X的第二个类型参数确定其返回类型,但是对于a,编译器被告知要丢弃它。所以b只是一个Any。使用REPL更容易看到:

scala> val a: X[_, _] = new Test
a: X[_, _] = Test@27abe2cd

scala> val b = a.providesY
b: Any = Test@f5f2bb7


因此,b.doesX无法编译,因为编译器现在认为它是Any。一种简单的解决方案是不要对类型使用通配符(或通常在任何情况下都不存在的任何存在性类型)。

scala> val a: X[Int, Test] = new Test
a: X[Int,Test] = Test@1134affc

scala> val b = a.providesY
b: Test = Test@6fc6f14e

scala> b.doesX
etc..


或者,您可以简单地取消类型注释,然后让编译器推断正确的类型。

09-30 15:09
查看更多