在Scala中A <:B和+ B有什么区别?
有什么区别
[A <: B]
和
[+B]
在斯卡拉?
Q[A <: B]
表示Q
类可以接受任何B
类的子类A
Q[+B]
表示Q
可以取任何类,但如果A
是B
一个子类,则Q[A]
被认为是Q[B]
一个子类。
Q[+A <: B]
表示类Q
只能传递B
的子类以及传播子类关系。
第一个是有用的,当你想要做一些通用的,但你需要依靠B
的某些方法。 例如,如果您有一个带有toFile
方法的Output
类,那么可以在任何可以传入Q
类中使用该方法。
第二个是有用的,当你想使集合的行为与原始类相同的方式。 如果你拿B
并且你创build了一个子类A
,那么你可以在任何需要B
地方传递A
但是如果你拿B
, Q[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/