Kotlin泛型超级/子类

TGI*_*GIO 2 generics kotlin

尝试使用泛型类型类,但遇到以下问题,即:

类型不匹配:推断的类型是ChildClassSuperClass<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
    }
}
Run Code Online (Sandbox Code Playgroud)

这是要点科特林游乐场

所需的结果是函数 testType(superClass: SuperClass<SuperType>) 应在 不使用通配符的情况下接受类ChildClass() *

hot*_*key 6

由于泛型差异,您的代码无法正常工作。SuperClass被定义为

open class SuperClass<T> where T: SuperType { ... }
Run Code Online (Sandbox Code Playgroud)

并且其类型参数T被声明为不变的(它没有outin修饰符)。因此,子类型关系如下:

  • DerivedClass<ChildType>不是的子类型SuperClass<SuperType>
  • SuperClass<ChildType>不是的子类型SuperClass<SuperType>
  • DerivedClass<SuperType> 的子类型SuperClass<SuperType>

由于函数参数应该属于参数类型的子类型,并且ChildClass实际上是DerivedClass<ChildType>,因此您不能将其ChildClass作为传递SuperClass<SuperType>

您可以通过将out投影添加到参数类型来解决此问题testType

fun testType(superClass: SuperClass<out SuperType>)
Run Code Online (Sandbox Code Playgroud)

这基本上意味着该函数接受SuperClass<T>where T是的子类型SuperType。当然,它在superClass用法上增加了一些限制:T绝对可以是的任何子类型SuperType,将任何内容传递给期望T作为参数的函数都是不安全的,因此禁止这样做。

另外,请参见另一个答案,该答案解释了不变泛型行为的原因:(链接)