Kotlin重写泛型变量编译失败,该如何调整代码实现需求?
问题原因
Kotlin 中带*星投影的var属性因为同时支持读和写,编译器会限制可赋值的类型:对于InputField<*>类型的var,读取时值类型为Any?,写入时仅允许传入Nothing类型(实际无法写入任何合法值),子类用具体泛型类型重写var时无法满足父类的类型契约,因此编译失败。
解决方案
有两种符合需求的调整方式,可按需选择:
方案1:给InputField添加声明处协变(推荐,完全匹配你的需求)
你的InputField接口只有生产泛型值的collectInput方法,没有消费泛型的逻辑,完全可以给泛型参数加out协变修饰,即可合法重写属性:
// 给T加out修饰,声明InputField是生产者类,仅输出T类型值 interface InputField<out T> { fun collectInput(): T } interface FieldComponent { // 协变后星投影的属性可以作为val对外暴露,不感知具体泛型类型 val myfield: InputField<*> } class NumberField(): FieldComponent{ // Kotlin允许子类用var重写父类的val属性,符合类型契约 override lateinit var myfield: InputField<Int> fun doSomething(){ val x: Int = myfield.collectInput() } } class TextField(): FieldComponent{ override lateinit var myfield: InputField<String> fun doSomething(){ val x: String = myfield.collectInput() } }
调整后持有FieldComponent实例时可以正常访问myfield属性,调用collectInput得到Any?类型的返回值,需要时可自行强转成对应类型使用。
方案2:给FieldComponent添加泛型参数
如果你确实需要外部可以修改myfield属性(必须保留var定义),可以给接口加泛型参数:
interface FieldComponent<T> { var myfield: InputField<T> } interface InputField<T> { fun collectInput(): T } class NumberField(): FieldComponent<Int>{ override lateinit var myfield: InputField<Int> fun doSomething(){ val x: Int = myfield.collectInput() } } class TextField(): FieldComponent<String>{ override lateinit var myfield: InputField<String> fun doSomething(){ val x: String = myfield.collectInput() } }
需要不感知泛型持有FieldComponent实例时,直接声明为FieldComponent<*>类型即可,和你最初的使用逻辑一致。
内容的提问来源于stack exchange,提问作者BabyishTank
相关产品推荐
相关产品推荐

