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

这两者有什么区别

[A <: B]

还有

[+B]

在斯卡拉?

12695 次浏览

我的理解是:


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


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


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

Scala:-Java: ? super T 逆变子类化

Q[A <: B]意味着类 Q可以接受任何类 A,它是 B的子类。

Q[+B]意味着 Q可以取 任何类,但是如果 AB的一个子类,那么 Q[A]就被认为是 Q[B]的一个子类。

Q[+A <: B]意味着类 Q只能接受 B的子类以及传播子类关系。

当您想要执行某些泛型操作时,第一种方法非常有用,但是您需要依赖于 B中的某组方法。例如,如果您有一个带有 toFile方法的 Output类,您可以在任何可以传递到 Q的类中使用该方法。

当希望使集合的行为与原始类的行为相同时,第二种方法非常有用。如果你取 B并且创建一个子类 A,那么你可以在 B预期的任何地方传递 A。但是,如果你采取 BA0,Q[B],这是真的,你总是可以通过 Q[A]而不是?一般来说,不会; 有些情况下,这样做是错误的。但是您可以说,通过使用 +B(协方差; Q协变量——以及—— B的子类的继承关系)来完成这项工作是正确的。

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

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

我想用更多的例子来扩展 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 的开发者并没有强制执行,例如只有汽车可以进入 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]参数,也可以将 List[Dog]作为参数传递给函数。由于列表的协方差。如果 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())
^
*/

正如你所看到的 谷仓是专门为动物准备的收藏品。这里禁止车辆进入。