因此,这就是我不断使用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
您正在告诉编译器
a
是X
,在这里您无需关心其类型参数是什么。也就是说,假定无界通配符_
的上限是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..
或者,您可以简单地取消类型注释,然后让编译器推断正确的类型。