具有类型绑定的协变类型的隐式解析失败

问题描述 投票:0回答:1

以下代码编译:

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

scala implicit contravariance generic-variance
1个回答
0
投票

[T <: U-TU的子类型。

如果使用协变量T-+T <:> U-TU的子类型,我们允许将T转换为其子类型。它的工作原理是-如果您有S <: T并将其替换为TT <: 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-TU的子类型,我们允许将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]则不会,这就是为什么一个示例编译而另一个示例失败的原因。

© www.soinside.com 2019 - 2024. All rights reserved.