无法推断逆变Nothing类型参数

时间:2017-10-09 09:06:31

标签: scala scala-compiler

请考虑以下代码段:

trait X[-T]
object Y extends X[Nothing]
def a[T](x: X[T]): X[T] = x
a(Y)

以上(2.12.3)的汇编失败,并且:

type mismatch;
found   : Y.type
required: X[T]
   a(Y)
     ^

如果符合以下条件,则编译正常:

  • 使用了与Nothing不同的类型(例如object Y extends X[String]
  • 方法a在其返回类型中不使用T(例如def a[T](x: X[T]): Unit = {}
  • 明确指定a的类型参数(即a[Nothing](Y)
  • T是协变的,而不是逆变的(如果它不变则也会失败)

这是Nothing的编译器中的一些特例吗?

作为一个有趣的"解决方法,以下似乎工作正常:

trait X[-T]
object Y extends X[Nothing]
def a[T, U <: T](x: X[T]): X[U] = x
a(Y)

1 个答案:

答案 0 :(得分:1)

我将尝试逐行解释代码

第1行:trait X[-T] - &gt;特征X在类型T中是逆变的。因此,您可以用其子类型替换X [T]类型的任何变量。在逆变类型的情况下,如果B是A的子类型,则Z [A]是Z [B]的子类型。

第2行:object Y extends X[Nothing] - &gt;对象Y的类型为X [Nothing]。请注意,Nothing不是所有其他类型的子类型。

第3行:def a[T](x: X[T]): X[T] = x - &gt;定义一个带有X [T]类型参数的表达式。因为特征X在类型T中是逆变的,所以你也可以传递X [T]的子类型,即X [N],使得T是N的子类型

第4行:a(Y) - &gt;使用类型X [Nothing]的参数调用表达式“a”。由于编译器不知道'a'的参数类型,因此无法确定X [Nothing]是否是X [T]的子类型。有多种方法可以解决此问题

Solution 1: `a[Nothing]` -> explicitly defining the type

Solution 2: `tait X[+T]` -> make X covariant in type T. In this case Z[A] is subtype of Z[B] if A is subtype of B. This will work because Nothing is subtype of any other type