В чем разница между <: B и +B в Scala?
Вопрос
В чем разница между
[A <: B]
а также
[+B]
в Скале?
Решение
Q[A <: B]
означает этот класс Q
может взять любой класс A
это подкласс B
.
Q[+B]
Значит это Q
может взять Любые класс, но если A
это подкласс B
, тогда Q[A]
считается подклассом Q[B]
.
Q[+A <: B]
означает этот класс Q
может взять только подклассы B
а также распространять отношения подкласса.
Первый полезен, когда вы хотите сделать что -то общее, но вам нужно полагаться на определенный набор методов в B
. Анкет Например, если у вас есть Output
класс с toFile
Метод, вы можете использовать этот метод в любом классе, который можно было бы перенести Q
.
Второй полезен, когда вы хотите сделать коллекции, которые ведут себя так же, как и исходные классы. Если вы возьмете B
и вы делаете подкласс A
, тогда вы можете пройти A
в любом месте, где B
ожидается. Но если вы возьмете коллекция из B
, Q[B]
, правда ли, что вы всегда можете пройти Q[A]
вместо? В общем, нет; Есть случаи, когда это было бы неправильно. Но вы можете сказать, что это правильно, используя +B
(ковариация; Q
ковари-следовать вместе с ...B
Соблаги на подклассах).
Другие советы
Я хотел бы продлить Отличный ответ Рекса Керра С еще некоторыми примерами: допустим, у нас есть четыре класса:
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() )
Как вы видете Список не заботится о том, содержит ли он животных или автомобили. Анкет Разработчики списка не обеспечили соблюдение того, что, например, только автомобили могут войти в списки.
Кроме того:
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[Dog]
считается подклассом List[Animal]
Из -за ковариации списка. Это не сработает, если список был инвариантным.
Теперь на границы типа:
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())
^
*/
Как вы видете Сарай - это коллекция, предназначенная только для животных. Анкет Здесь не разрешено автомобили.
Для моего понимания:
Первый - это граница типа параметров, в нашем случае верхний и нижний тип
Второе - это аннотация дисперсии для определения класса, в нашем случае ковариационная подклассирование B
Скала: + Java:? расширяет ковариантную подклассию
Скала: - Ява:? Super T Contravariant Подкласс
Я нашел этот пост в блоге, исследуя этот вопрос. Дает еще более глубокое объяснение дисперсии Scala, включая ее теоретическую основу в теории категории
http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/