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,则可以将其传递AB预期的任何位置.但是如果你收集了一个B,Q[B]那么你是否可以随时传入Q[A]?一般来说,没有; 有些情况下这是错误的做法.但是你可以说这是正确的做法+B(协方差; Qcovaries - 跟随 - B子类的继承关系).

  • 你能举例说明逆变器的使用吗?Q[-A] 是什么意思? (2认同)

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是一个仅供动物使用的系列.这里没有车.

  • `Animal`-`Dog` /`Car` -`SportsCar`类总是最好的例子.很难跟上所有那些"Q","A","B". (15认同)