有什么区别
[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--的子类的继承关系)。B
Q[B]
Q[A]
+B
Q
B
我想用更多的例子来扩展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 逆变子类化