有什么区别
[A <: B]
和
[+B]
在斯卡拉?
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
我想用更多的例子来扩展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 的集合。这里不允许汽车进入。
我在研究这个问题时发现了这篇博文。对 Scala 方差进行了更深入的解释,包括其在范畴论中的理论基础
http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/
为了我的理解:
第一个是参数类型界限,在我们的例子中,有一个上限和下限类型界限,它是一个“类型参数 A,它是 B 的子类型(或 B 本身)。
第二个是类定义的方差注释,在我们的例子中是 B 的协方差子类
斯卡拉:+ Java:?扩展 T 协变子类化
斯卡拉:-Java:?super T 逆变子类化