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


Answers:


170

Q[A <: B]表示该类Q可以采用A的子类的任何类B

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

Q[+A <: B]表示该类Q只能继承B和传播子类关系。

当您想做一些通用的事情,但是您需要依赖中的一组特定方法时,第一个很有用B。例如,如果您有一个Output带有toFile方法的类,则可以在可以传入的任何类中使用该方法Q

当您要使集合的行为与原始类相同时,第二个有用。如果您采用B并创建了一个子类A,则可以传递期望的A任何地方B。但是,如果你把一个集合BQ[B]是真的,你总是可以传递Q[A]呢?一般来说,不可以;在某些情况下,这样做是错误的。但是您可以说这是使用+B(covariance; Qcovaries-以及-'subclasses B'继承关系)正确的做法。


2
您可以举例说明一下如何使用逆变吗?Q [-A]是什么意思?
moshe beeri 2014年

45

我想通过更多示例来扩展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可以进入List。

另外:

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是仅用于动物的集合。禁止车辆进入。


15
Animal- Dog/ Car-SportsCar类始终是最佳示例。这是非常难以遵循所有这些QAB秒。
Namek

List[Car]我们当然可以添加SportsCar,即使它被宣布为 List[B]。如果我们具有like函数def smth(x:MyList[Car]):Unit = {},则传递List[SportsCar]将失败List[B],但不会失败List[+B],因为现在List[SportsCar]是的子类List[Car],并且可以传递子类代替原始类。
Zxcv Mnb '17

2

据我了解:


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


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


Scala:+ Java :?扩展T协变量子类

Scala:-Java :?超级T逆子分类


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.