Родственные классы супер / дочерние классы Котлина

Попытка использовать классы общих типов, но получила следующую проблему:

Тип несоответствия: выведенный тип – ChildClass но SuperClass<SuperType> ожидался

 open class SuperClass<T> where T: SuperType { fun modifySomething(input: T): T { input.someValue.inc() return input } } open class SuperType { val someValue: Int = 0 } class ChildClass : SuperClass<ChildType>() class ChildType: SuperType() { fun getModifiedValue(): Int { return someValue } } class TestEnvironment { fun testType(superClass: SuperClass<SuperType>) { // do something with superClass } fun itDoesntWork() { testType(ChildClass()) // compilation error } } 

Вот суть и игровая площадка kotlin

Желаемый результат состоит в том, что функция testType(superClass: SuperClass<SuperType>) должна принимать класс ChildClass() без использования * wildcard

Это различие генериков, который не позволяет вашему коду работать. SuperClass определяется как

 open class SuperClass<T> where T: SuperType { ... } 

И его параметр типа T объявляется как инвариантный (он не имеет out или in модификаторах). Поэтому отношения подтипирования заключаются в следующем:

  • DerivedClass<ChildType> не является подтипом SuperClass<SuperType>
  • SuperClass<ChildType> не является подтипом SuperClass<SuperType>
  • DerivedClass<SuperType> это подтип SuperClass<SuperType> .

Поскольку аргумент функции должен принадлежать подтипу типа параметра, а ChildClass – фактически DerivedClass<ChildType> , вы не можете передать ChildClass в качестве SuperClass<SuperType> .

Вы можете решить эту проблему, добавив проекцию в тип параметра testType :

 fun testType(superClass: SuperClass<out SuperType>) 

Это в основном означает, что эта функция принимает SuperClass<T> где T является подтипом SuperType . Конечно, это добавляет определенные ограничения на использование superClass : поскольку T может быть абсолютно любым подтипом SuperType , он не безопасен для типов передавать что-либо функциям, которые ожидают T как аргумент, и это запрещено.

Также см. Другой ответ, объясняющий причину поведения инвариантных дженериков: (link)