在Scala中A <:B和+ B有什么区别?

有什么区别

[A <: B] 

 [+B] 

在斯卡拉?

Q[A <: B]表示Q类可以接受任何B类的子类A

Q[+B]表示Q可以取任何类,但如果AB一个子类,则Q[A]被认为是Q[B]一个子类。

Q[+A <: B]表示类Q只能传递B的子类以及传播子类关系。

第一个是有用的,当你想要做一些通用的,但你需要依靠B的某些方法。 例如,如果您有一个带有toFile方法的Output类,那么可以在任何可以传入Q类中使用该方法。

第二个是有用的,当你想使集合的行为与原始类相同的方式。 如果你拿B并且你创build了一个子类A ,那么你可以在任何需要B地方传递A 但是如果你拿BQ[B]集合 ,那么你是否可以总是通过Q[A]而不是? 一般来说,没有; 有些情况下,这是错误的事情。 但是你可以说,通过使用+B (协方差; Q协variables – 跟随 – B的子类的inheritance关系)是正确的。

我想用一些例子来扩展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的开发人员并没有强制执行,例如只有Cars才能进入列表。

另外:

 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]参数,您也可以将List[Dog]作为parameter passing给函数。 List[Dog]由于List的协方差而被认为是 List[Animal] 一个子类 。 如果List是不变的,它将不起作用。

现在到types边界:

 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()) ^ */ 

正如你可以看到谷仓是一个只为动物专用的集合 。 没有车在这里允许。

对于我的理解:


第一种是绑定的参数types,在我们的例子中有一个上下限的typebounds,它的types参数A是B(或B本身)的子types。


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


斯卡拉:+ Java:? 扩展T Covariant子类

斯卡拉: – Java:? 超T逆变式子类化

我在研究这个问题的时候发现了这篇博文。 给出了Scala方差的更深层的解释,包括它在分类理论中的理论基础

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