Здравствуйте, Аноним, Вы писали:
А>Но что значит вот этот текст?
А>А>The annotation +T declares type T to be used only in covariant positions. Similarly, -T would declare T to be used only in contravariant positions. For covariant type parameters we get a covariant subtype relationship regarding this type parameter. For our example this means Stack[T] is a subtype of Stack[S] if T is a subtype of S. The opposite holds for type parameters that are tagged with a -.
А>Может кто-то объяснить по-русски и с примерами?
Ковариантный — значит "меняющийся в ту же сторону". Контравариантный — "меняющийся в обратную сторону".
Классические дженерики C# (версии ниже 4.0) и Java не поддерживают ко-/контравариантности. Это значит, что, например, не будет неявного преобразования от типа List<String> к List<Object> несмотря на то, что String является подтипом типа Object. Ясно, что в общем случае ковариантность не типобезопасна: иначе мы могли бы привести List<String> к List<Object> и затем положить туда Integer, после чего могли бы попытаться извлечь этот элемент из исходной переменной типа List<String>, которая ссылается на тот же объект — ясно, что это закончилось бы тем, что в худшем случае в переменной типа String оказался бы Integer, а в лучшем мы получили бы ClassCastException в неожиданном месте (там, где нет явного приведения типов). Поэтому самое простое решение — запретить коваринатность вообще. Scala принимает более изящное решение: разделять позиции в коде, на которых может встречаться тип-параметр (например: декларация параметра метода, декларация возвращаемого значения, декларация локальной переменной и т.д.) на ковариантные, контравариантные и инвариантные в зависимости от того, окажется ли это типобезопасным при разрешенных приведениях типов.
И если некоторый тип-параметр встречается только в ковариантных позициях, то он может быть объявлен ковариантным (+T). Другими словами: если он объявлен ковариантным, то он обязан встречаться только в ковариантных позициях. Аналогичная ситуация в C# 4.0, за исключением, что ко-/контравариантные типы-параметры быть только у интерфейсов и делегатов, но не у любых классов.
Соответственно, если параметр T у класса C — коавариантный, то тип C[B] будет считаться подтипом типа C[A] (и будет неявно приводим к типу С[A]), если тип В является подтипом типа A.
И наоборот, если параметр T у класса C — контравариантный, то тип C[A] будет считаться подтипом типа C[B] (и будет неявно приводим к типу С[B]), если тип В является подтипом типа A.
Последняя ситуация имеет смысл, например, для такого класса (умеющего сравнивать объекты типа T):
class Comparer[-T] {
def Compare(x : T, x : T) : Boolean = { /* ... */ }
}
Объект типа Comparer[Object] умеет сравнивать любые объекты, значит он умеет сравнивать и строки. Ясно, что его можно безопасно неявно привести к типу Comparer[String]. Для компилятора здесь существенно то, что тип T появляется только в качестве типа параметров метода — эти позиции контравариантны.
Для инвариантных типов-параметров, между C[A] и C[B] нет неявных преобразований ни в какую сторону (если типы A и B различны).