以下代码编译:
class X[U, T <: U]
object X {
implicit def genericX[U, T <: U]: X[U, T] = new X[U, T]
}
implicitly[X[String, String]] // compiles
[当我们使T
协变(class X[U, +T <: U]
)时也将进行编译:
class X[U, +T <: U]
object X {
implicit def genericX[U, T <: U]: X[U, T] = new X[U, T]
}
implicitly[X[String, String]] // compiles
[当我们使T
为逆变(class X[U, -T <: U]
)时,编译器无法使implicitly[X[String, String]]
失效。足够奇怪的是,它能够实现implicitly[X[Any, Any]]
:
class X[U, -T <: U]
object X {
implicit def genericX[U, T <: U]: X[U, T] = new X[U, T]
}
implicitly[X[Any, Any]] // compiles
implicitly[X[String, String]] // error: could not find an implicit value
[我怀疑尽管有显式的类型注释,但处于相反位置的类型T
被过早地固定为Any
。这是预期的行为吗?
加分点:如果我们修复了T
,反变量U
确实起作用:
class X[-T <: String]
object X {
implicit def genericX[T <: String]: X[T] = new X[T]
}
implicitly[X[String]] // compiles
[T <: U
-T
是U
的子类型。
如果使用协变量T-+T
<:> U
-T
是U
的子类型,我们允许将T
转换为其子类型。它的工作原理是-如果您有S <: T
并将其替换为T
的T <: U
,则会得到S <: U
的事实。
trait A
trait B extends A
trait C extends B
// the value of
X[A, B] // can be used as
X[A, C] // because of covariance
// this doesn't violate B <: A nor C <: A
如果使用逆变T-+T
<:> U
-T
是U
的子类型,我们允许将T
转换为其超类型。
trait A
trait B extends A
trait C extends B
// the value of
X[B, C] // you want to be allowed to be used as
X[B, B] // or because of contravariance as
X[B, A]
// while B <: B, so it's ok, you cannot A <: B! so there a counterexample
在其他作品中,编译器可以证明这种对立性和类型界限的组合通常是一个坏主意。 Any
有点特别,因为它是顶级类型-您无法获得更高的价格。因此,充其量您会生成Any
尽管是自变量,而不是某些“ Any的超类型”,因为它不存在(而对于任何其他类型总是有一个超类型-例如,Any)。
因此,对于X[Any Any]
编译器可以证明矛盾不会造成任何损害,而对于X[String, String]
则不会,这就是为什么一个示例编译而另一个示例失败的原因。