具有多个约束的协方差类型参数

Covariance type parameter with multiple constraints

我正在学习 Scala 中类型变化和边界的概念以及如何使用它们。我遇到了以下关于堆栈溢出的问题,其中一个解决方案提到了如何防止 scala 泛化类型。

下面是解决方案中发布的代码。在下面的代码中,添加一个新的类型参数 C 有什么帮助?我了解 B 是如何受到约束的(作为 A 的超类型和 Fruit 的子类型)。但是我完全不知道 C 在这里做了什么。为什么它应该是A的超类型。为什么隐含证据要求B是C的子类型?

以及为什么在添加 Fruit 不是 Banana 的子类型的 Orange 对象列表时出现不相关的错误。有人可以解释一下吗?

我猜是为了满足第一个约束条件,Orange 对象被推断为 Fruit 对象,但之后就不知道为什么它说 Fruit 不是 Banana 的子类型了。

case class Banana() extends Fruit
defined class Banana

case class Orange() extends Fruit
defined class Orange

case class Basket[+A <: Fruit](items: List[A]) {
    // ...
    def addAll[B >: A <: Fruit, C >: A](newItems: List[B])(implicit ev: B <:< C): Basket[B] =
  new Basket(items ++ newItems)
    // ...
  }
defined class Basket

val bananaBasket: Basket[Banana] = Basket(List(Banana(), Banana()))
bananaBasket: Basket[Banana] = Basket(List(Banana(), Banana()))

bananaBasket.addAll(List(Orange())) // not accepted
Main.scala:593: Cannot prove that Product with Serializable with cmd27.Fruit <:< cmd47.Banana.
bananaBasket.addAll(List(Orange()))

语法

def foo[A >: LA <: UA, B...](...)(implicit ev: F[A, B] <:< G[A, B], ...)

表示

  • 首先应该推断出A, B ...以满足条件A >: LA <: UA, B...
  • 其次,对于这些推断的 A, B ... 条件 F[A, B] <:< G[A, B], ... 应该进行检查。

基本上 C >: Aev: B <:< C 的意思是(因为 C 无处使用,编译器正在寻找 C 的最低上限)CA,为此我们应该检查 B <:< A。只是我们不能删除 C >: A 并用 ev: B <:< A 替换 ev: B <:< C,因为那样我们就会有 Error: covariant type A occurs in contravariant position in type B <:< A of value ev.

所以我们希望 B 被推断为 B >: A <: Fruit (即 B 应该是 A 超类型 ) 并为此 B 检查 B <:< A(即 B 应该是 A 子类型 )。所以这个只有在A = B的时候才能满足。这会阻止 bananaBasket.addAll(List(Orange())) 编译。