72

有什么区别

[A <: B]

[+B]

在斯卡拉?

4

4 回答 4

179

Q[A <: B]意味着 classQ可以采用任何A属于B.

Q[+B]表示Q可以取任何类,但如果A是 的子类B,则Q[A]认为是 的子类Q[B]

Q[+A <: B]意味着类Q只能获取子类B以及传播子类关系。

当您想要做一些通用的事情时,第一个很有用,但是您需要依赖B. 例如,如果您有一个Output带有toFile方法的类,您可以在任何可以传递给Q.

当您想要创建与原始类的行为方式相同的集合时,第二个很有用。如果您选择B并创建了一个 subclass A,那么您可以在任何预期A的地方传递。B但是如果你取一个,的集合,是不是总是可以传入呢?一般来说,没有;在某些情况下,这样做是错误的。但是您可以说这是正确的做法,使用(covariance; covaries--follows with--的子类的继承关系)。BQ[B]Q[A]+BQB

于 2010-12-25T21:08:04.133 回答
46

我想用更多的例子来扩展Rex Kerr 的优秀答案:假设我们有四个类:

 class Animal {}
 class Dog extends Animal {}

 class Car {}
 class SportsCar extends Car {}

让我们从方差开始:

 case class List[+B](elements: B*) {} // simplification; covariance like in original List

 val animals: List[Animal] = List( new Dog(), new Animal() )
 val cars: List[Car] = List ( new Car(), new SportsCar() )

如您所见, List 不关心它是否包含 Animals 或 Cars。List 的开发者并没有强制例如只有 Cars 可以进入 Lists。

此外:

case class Shelter(animals: List[Animal]) {}

val animalShelter: Shelter = Shelter( List(new Animal()): List[Animal] )
val dogShelter: Shelter = Shelter( List(new Dog()): List[Dog] )

如果函数需要List[Animal]参数,您也可以将 aList[Dog]作为参数传递给函数。由于 List 的协方差,List[Dog] 被认为是的子类。 List[Animal]如果 List 是不变的,它将不起作用。

现在进入类型边界:

case class Barn[A <: Animal](animals: A*) {}

val animalBarn: Barn[Animal] = Barn( new Dog(), new Animal() )
val carBarn = Barn( new SportsCar() )
/* 
error: inferred type arguments [SportsCar] do not conform to method apply's type parameter bounds [A <: Animal]
    val carBarn = Barn(new SportsCar())
                 ^
*/

如您所见,Barn 是仅适用于 Animals 的集合。这里不允许汽车进入。

于 2014-02-27T21:12:44.323 回答
2

我在研究这个问题时发现了这篇博文。对 Scala 方差进行了更深入的解释,包括其在范畴论中的理论基础

http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/

于 2013-09-20T17:28:35.830 回答
2

为了我的理解:


第一个是参数类型界限,在我们的例子中,有一个上限和下限类型界限,它是一个“类型参数 A,它是 B 的子类型(或 B 本身)。


第二个是类定义的方差注释,在我们的例子中是 B 的协方差子类


斯卡拉:+ Java:?扩展 T 协变子类化

斯卡拉:-Java:?super T 逆变子类化

于 2010-12-25T20:14:07.017 回答