有什么区别
[A <: B]
Run Code Online (Sandbox Code Playgroud)
和
[+B]
Run Code Online (Sandbox Code Playgroud)
在斯卡拉?
Rex*_*err 168
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
预期的任何位置.但是如果你收集了一个B
,Q[B]
那么你是否可以随时传入Q[A]
?一般来说,没有; 有些情况下这是错误的做法.但是你可以说这是正确的做法+B
(协方差; Q
covaries - 跟随 - B
子类的继承关系).
muc*_*aho 45
我想用更多的例子来扩展Rex Kerr的优秀答案:假设我们有四个类:
class Animal {}
class Dog extends Animal {}
class Car {}
class SportsCar extends Car {}
Run Code Online (Sandbox Code Playgroud)
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() )
Run Code Online (Sandbox Code Playgroud)
如您所见,List并不关心它是否包含动物或汽车.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] )
Run Code Online (Sandbox Code Playgroud)
如果函数需要List[Animal]
参数,您也可以将a List[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())
^
*/
Run Code Online (Sandbox Code Playgroud)
正如您所见,Barn是一个仅供动物使用的系列.这里没有车.