type parameter implicitly classes scala variance

parameter - ¿Cuál es la diferencia entre A<: B y+B en Scala?



scala type (4)

Cuál es la diferencia entre

[A <: B]

y

[+B]

en Scala?



Me gustaría extender la excelente respuesta de Rex Kerr con algunos ejemplos más: digamos que tenemos cuatro clases:

class Animal {} class Dog extends Animal {} class Car {} class SportsCar extends Car {}

Comencemos con la varianza:

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

Como puede ver, a List no le importa si contiene Animals o Cars . Los desarrolladores de List no hicieron cumplir que, por ejemplo, solo los automóviles pueden entrar dentro de listas.

Adicionalmente:

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 una función espera un parámetro List[Animal] también puede pasar una List[Dog] como argumento a la función. List[Dog] se considera una subclase de List[Animal] debido a la covarianza de List. No funcionaría si List fuera invariante.

Ahora en los límites de tipo:

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

Como puedes ver, Barn es una colección solo para Animales . No se permiten autos aquí.


Para mi entendimiento:

El primero es un tipo de parámetro vinculado, hay un tipo de letra superior e inferior en nuestro caso es un "tipo de parámetro A que es un subtipo de B (o B mismo).

El segundo es una anotación de varianza para una definición de clase, en nuestro caso una subclasificación de covarianza de B

Scala: + Java:? extiende la subclasificación T covariante

Scala: - Java:? superc T Subclase contravariante


Q[A <: B] significa que la clase Q puede tomar cualquier clase A que sea una subclase de B

Q[+B] significa que Q puede tomar cualquier clase, pero si A es una subclase de B , entonces Q[A] se considera una subclase de Q[B] .

Q[+A <: B] significa que la clase Q solo puede tomar subclases de B y propagar la relación de subclase.

El primero es útil cuando quiere hacer algo genérico, pero necesita basarse en cierto conjunto de métodos en B Por ejemplo, si tiene una clase de Output con un método toFile , puede usar ese método en cualquier clase que se pueda pasar a Q

El segundo es útil cuando quiere hacer colecciones que se comporten de la misma manera que las clases originales. Si tomas B y haces una subclase A , entonces puedes pasar A en cualquier lugar donde se espera B Pero si tomas una colección de B , Q[B] , ¿es verdad que siempre puedes pasar Q[A] ? En general, no; hay casos en que esto sería lo incorrecto. Pero puede decir que esto es lo correcto al usar +B (covarianza; Q covarios - sigue junto con-- la relación de herencia de las subclases de B ).