2017-10-09 64 views
10

考虑下面的代码片段:无法推断逆变全无类型参数

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

我会尝试通过行解释代码行

线路1:trait X[-T] - >特征X是在T类型中是不变的。所以你可以用它的子类型来替换任何类型为X [T]的变量。在逆变类型的情况下,如果B是A的子类型,Z [A]是Z [B]的子类型。

线2:object Y extends X[Nothing]→对象Y是X型[无]。请注意,Nothing是所有其他类型的子类型。

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

第4行:a(Y) - >用参数类型调用表达式'a' X [没什么]。由于编译器不知道'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 
+0

感谢您的回答,但为什么使用String而不是Nothing来让示例编译?或者为什么解决方法工作? – adamw