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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4531455/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 02:41:17  来源:igfitidea点击:

What's the difference between A<:B and +B in Scala?

scalavariance

提问by jsadfeew

What's the difference between

有什么区别

[A <: B]

and

[+B]

in Scala?

在斯卡拉?

回答by Rex Kerr

Q[A <: B]means that class Qcan take any class Athat is a subclass of B.

Q[A <: B]意味着该类Q可以采用A作为 的子类的任何类B

Q[+B]means that Qcan take anyclass, but if Ais a subclass of B, then Q[A]is considered to be a subclass of Q[B].

Q[+B]意味着Q可以取任何类,但如果A是 的子类BQ[A]则被认为是 的子类Q[B]

Q[+A <: B]means that class Qcan only take subclasses of Bas well as propagating the subclass relationship.

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

The first is useful when you want to do something generic, but you need to rely upon a certain set of methods in B. For example, if you have an Outputclass with a toFilemethod, you could use that method in any class that could be passed into Q.

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

The second is useful when you want to make collections that behave the same way as the original classes. If you take Band you make a subclass A, then you can pass Ain anywhere where Bis expected. But if you take a collectionof B, Q[B], is it true that you can always pass in Q[A]instead? In general, no; there are cases when this would be the wrong thing to do. But you can say that this is the right thing to do by using +B(covariance; Qcovaries--follows along with--B's subclasses' inheritance relationship).

当您想要使集合的行为方式与原始类相同时,第二个很有用。如果您使用B并创建一个 subclass A,那么您可以AB预期的任何地方传递。但是,如果你把一个集合BQ[B]是真的,你总是可以传递Q[A]呢?一般来说,没有;在某些情况下,这是错误的做法。但是您可以说这是通过使用+B(covariance; Qcovaries--follows with-- B'subclasses' 继承关系)来做的正确的事情。

回答by mucaho

I would like to extend Rex Kerr's excellent answerwith some more examples: Let's say we have four classes:

我想用更多的例子来扩展Rex Kerr 的出色回答:假设我们有四个类:

 class Animal {}
 class Dog extends Animal {}

 class Car {}
 class SportsCar extends Car {}

Let's start with variance:

让我们从方差开始:

 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() )

As you can see List does not care whether it contains Animals or Cars. The developers of List did not enforce that e.g. only Cars can go inside Lists.

如您所见,List 并不关心它是否包含 Animals 或 Cars。List 的开发者并没有强制要求例如只有 Cars 才能进入 Lists。

Additionally:

此外:

case class Shelter(animals: List[Animal]) {}

val animalShelter: Shelter = Shelter( List(new Animal()): List[Animal] )
val dogShelter: Shelter = Shelter( List(new Dog()): List[Dog] )

If a function expects a List[Animal]parameter you can also pass a List[Dog]as an argument to the function instead. List[Dog]is considered a subclass ofList[Animal]due to the covariance of List. It would not work if List was invariant.

如果函数需要List[Animal]参数,您也可以将 aList[Dog]作为参数传递给函数。由于 List 的协方差,List[Dog]被认为是 的子类List[Animal]。如果 List 是不变的,它将不起作用。

Now onto type bounds:

现在进入类型边界:

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())
                 ^
*/

As you can see Barn is a collection only intended for Animals. No cars allowed in here.

如您所见,Barn 是一个仅适用于 Animals 的集合。这里禁止车辆进入。

回答by Michele

for my Understanding:

我的理解:



The first is a parameter type bound, there a upper and lower typebounds in our case its a "type parameter A that is a subtype of B (or B itself).

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



The second is a Variance Annotation for a class defintion, in our case a covariance subclassing of B

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



Scala: + Java: ? extends T Covariant subclassing

斯卡拉:+ Java:?扩展 T 协变子类

Scala: - Java: ? super T Contravariant subclassing

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

回答by Totoro

I found this blog post while researching this question. Gives an even deeper explanation of Scala variance including its theoretical basis in Category Theory

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

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

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