【问题标题】:Kotlin generics super/child classesKotlin 泛型超/子类
【发布时间】:2017-04-17 14:50:01
【问题描述】:

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

类型不匹配:推断类型为 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&lt;SuperType&gt;) 应该接受类 ChildClass() 不使用* 通配符

【问题讨论】:

  • 请在问题中包含代码。

标签: generics kotlin


【解决方案1】:

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

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

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

  • DerivedClass&lt;ChildType&gt; 不是 SuperClass&lt;SuperType&gt; 的子类型
  • SuperClass&lt;ChildType&gt; 不是 SuperClass&lt;SuperType&gt; 的子类型
  • DerivedClass&lt;SuperType&gt; SuperClass&lt;SuperType&gt;的子类型。

由于函数参数应该属于参数类型的子类型,而ChildClass实际上是DerivedClass&lt;ChildType&gt;,所以不能将ChildClass作为SuperClass&lt;SuperType&gt;传递。

您可以通过在testType的参数类型中添加out projection来解决这个问题:

fun testType(superClass: SuperClass<out SuperType>)

这基本上意味着该函数接受SuperClass&lt;T&gt;,其中TSuperType 的子类型。当然,它对superClass 的使用增加了某些限制:由于T 绝对可以是SuperType 的任何子类型,因此将任何内容传递给期望T 作为参数的函数不是类型安全的,而这被禁止。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-17
    • 2021-11-15
    • 1970-01-01
    相关资源
    最近更新 更多