所以这就是我在Scala遇到的各种情况下遇到的问题 - 它似乎忽略了隐含的类型,即使情况很明显。当然,这可能是我承认的理解,但是当涉及到下划线的占位符时,我一直遇到麻烦。例如下面(这是虚构的,只是为了证明这一点)。特质X的第二个位置必须是某种类型的<:X [,]。这里没有歧义 - 所以scala看到这个位置的任何地方,无论它的编码有多么弱 - 联系人都是X,我应该可以访问类似" doX"等功能。这不是无可争议的吗?无论我在代码中处理那个位置有多糟糕,我都必须至少得到X.为什么当你深入到类型系统时,Scala会不断忽略这个事实?任何指针都将不胜感激,谢谢!
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
}
答案 0 :(得分:7)
当你写:
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..
或者您可以简单地省略类型注释,让编译器推断出正确的类型。