Kotlin仿制品超级/子类

时间:2017-04-17 14:50:02

标签: generics kotlin

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

  

类型不匹配:推断类型为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
    }
}

以下是the gistthe kotlin playground

期望的结果是该功能 testType(superClass: SuperClass<SuperType>) 应该接受类 ChildClass() 而不使用*通配符

1 个答案:

答案 0 :(得分:4)

generics variance阻止您的代码正常工作。 SuperClass定义为

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

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

  • DerivedClass<ChildType> <{1}}
  • 的子类型
  • SuperClass<SuperType> <{1}}
  • 的子类型
  • SuperClass<ChildType> SuperClass<SuperType>的子类型。

由于函数参数应属于参数类型的子类型,而DerivedClass<SuperType>实际上是SuperClass<SuperType>,因此您无法将ChildClass作为DerivedClass<ChildType>传递。

您可以通过将out projection添加到参数类型ChildClass来解决此问题:

SuperClass<SuperType>

这基本上意味着此函数接受testType,其中fun testType(superClass: SuperClass<out SuperType>) SuperClass<T>的子类型。当然,它对T用法添加了一些限制:因为SuperType可以绝对是superClass的任何子类型,所以将任何内容传递给期望{{1}的函数都不是类型安全的作为参数,这是禁止的。

此外,请参阅另一个解释不变泛型行为的原因的答案:(link)