Question

Quelle est la différence entre

[A <: B]

et

[+B]

Scala?

Était-ce utile?

La solution

moyens de Q[A <: B] que Q de classe peut prendre toute A de classe qui est une sous-classe de B.

moyens de Q[+B] que Q peut prendre une classe , mais si A est une sous-classe de B, alors Q[A] est considéré comme une sous-classe de Q[B].

moyens de Q[+A <: B] que Q de classe ne peut prendre sous-classes de B ainsi que la propagation de la relation de sous-classe.

La première est utile lorsque vous voulez faire quelque chose de générique, mais vous devez compter sur un certain ensemble de méthodes B. Par exemple, si vous avez une classe Output avec une méthode toFile, vous pouvez utiliser cette méthode dans une classe qui pourrait être passé dans Q.

La seconde est utile lorsque vous voulez faire des collections qui se comportent de la même manière que les classes d'origine. Si vous prenez B et vous faites une A de sous-classe, alors vous pouvez passer dans A partout où B est prévu. Mais si vous prenez un collection de B, Q[B], est-il vrai que vous pouvez toujours passer Q[A] à la place? En général, non; il y a des cas où ce serait la mauvaise chose à faire. Mais vous pouvez dire que c'est la bonne chose à faire en utilisant +B. (Covariance; covarie de Q - suit avec - la relation d'héritage de sous-classes de B)

Autres conseils

Je voudrais étendre excellente réponse Rex Kerr avec quelques autres exemples: Disons que nous avons quatre classes:

 class Animal {}
 class Dog extends Animal {}

 class Car {}
 class SportsCar extends Car {}

Commençons Let avec la 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() )

Comme vous pouvez le voir Liste ne se soucie pas de savoir si elle contient les animaux ou les voitures . Les développeurs de la liste ne sont pas appliquer que par exemple Seules les voitures peuvent aller à l'intérieur des listes.

De plus:

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

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

Si une fonction attend un List[Animal] paramètre, vous pouvez également passer un List[Dog] comme argument à la fonction à la place. List[Dog] est considéré comme une sous-classe de List[Animal] en raison de la covariance de la liste. Il ne travaillerait si Liste était invariant.

Maintenant, sur des bornes de type:

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

Comme vous pouvez le voir Grange est une collection uniquement destiné aux animaux . Pas de voitures autorisées ici.

pour ma compréhension:


Le premier est un type de paramètre lié, il y a typebounds supérieure et inférieure dans notre cas, son paramètre de type A » A qui est un sous-type B (ou B lui-même).


La seconde est une Annotation variance pour une défintion de classe, dans notre cas une covariance B de sous-classement


Scala: + Java: étend T covariante sous-classement

Scala: - Java: super T contravariants sous-classement

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top