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

时间:2019-05-05 20:52:36

标签: scala types covariance

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

Covariant type parameter

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

为什么添加“水果”不是“香蕉”子类型的“橙色”对象列表时出现不相关的错误。有人可以解释一下吗?

我想满足第一个约束条件,即将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()))

1 个答案:

答案 0 :(得分:2)

语法

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 <:< C替换为ev: B <:< A,因为那样我们将拥有Error: covariant type A occurs in contravariant position in type B <:< A of value ev

因此,我们希望推断出B,以便B >: A <: Fruit(即B应该是A超类型),为此,{ {1}}检查B(即B <:< A应该是B子类型)。因此,只有在A时才能满足。这样可以防止A = B进行编译。