Quelle est la différence entre A <: B et + B à Scala?
Question
Quelle est la différence entre
[A <: B]
et
[+B]
Scala?
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
J'ai trouvé ce blog tout en recherchant cette question. Donne une explication encore plus profonde de la variance Scala y compris sa base théorique dans la catégorie Théorie
http://blogs.atlassian.com/2013 / 01 / covariance et-contravariance-en-scala /