为什么Scala有时会忽略明确定义的类型?

时间:2017-03-17 02:51:17

标签: scala generics types

所以这就是我在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

}

1 个答案:

答案 0 :(得分:7)

当你写:

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..

或者您可以简单地省略类型注释,让编译器推断出正确的类型。