我正在学习scala中类型差异和范围的概念以及如何使用它们。我遇到了有关堆栈溢出的以下问题,其中一个解决方案提到了如何防止Scala泛化类型。
下面是解决方案中发布的代码。在下面的代码中,添加新的类型参数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()))
答案 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 >: A
和ev: B <:< C
的平均值(因为C
在其他地方都没有使用,并且编译器正在寻找C
的最低上限),C
是A
,为此,我们应该检查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
进行编译。