为什么scala无法对f绑定多态进行类型推断?

时间:2017-02-11 20:44:24

标签: scala type-inference f-bounded-polymorphism

说明问题的简单示例:

trait WTF[W <: WTF[W]] {
  def get : Int
}

trait Zero extends WTF[Zero] {
  override def get : Int = 0
}
case object Zero extends Zero

final case class Box(inner : Int) extends WTF[Box] {
  override def get : Int = inner
}

def printWTF[W <: WTF[W]](w : W) = println(w.get)

printWTF(Box(-1))
printWTF(Zero)

Box没问题,但是Zero会产生错误:

WTF.scala:22: error: inferred type arguments [Zero.type] do not conform to method printWTF's type parameter bounds [W <: WTF[W]]
  printWTF(Zero)
  ^
WTF.scala:22: error: type mismatch;
 found   : Zero.type
 required: W
  printWTF(Zero)
           ^
two errors found

如果我手动注释类型,它会编译:

printWTF[Zero](Zero)
printWTF(Zero : Zero)

第一行按预期工作。我经常遇到无法从参数推断出类型参数的情况。例如def test[A](x : Int) : Unit。 <{1}}类型在参数签名中没有出现,因此您应该手动指定它。

但后者对我来说非常模糊。我刚刚添加了类型转换,它始终是真的,并且奇迹般地编译器学习如何推断方法类型参数。但是A始终是Zero类型,为什么编译器在没有提示的情况下无法推断它?

1 个答案:

答案 0 :(得分:2)

案例对象Zero的类型为Zero.type,是WTF[Zero]的子类型。因此,当您调用printWTF(Zero)时,编译器会推断W = Zero.type,但Zero.type <: WTF[Zero.type]为false,因此编译失败。

另一方面,这个更复杂的签名应该有效:

def printWTF[W <: WTF[W], V <: W](w: V with WTF[W]) = println(w.get)

作为一个证明,这确实正确地推断了类型:

scala> def printWTF[W <: WTF[W], V <: W](w: V with WTF[W]): (V, W) = ???
printWTF: [W <: WTF[W], V <: W](w: V with WTF[W])(V, W)

scala> :type printWTF(Box(1))
(Box, Box)

scala> :type printWTF(Zero)
(Zero.type, Zero)