通过子类来改变Kotlin中类型参数的变化
这个问题来源于我之前关于Kotlin泛型的问题 。 请在这里查看更多关于这个问题背后动机的信息。
我有一个类不受约束的类型参数
trait Handler<T> { fun handle(result: T) }
我需要创建一个Handler
实例,其中T
是List<O>
,因此是不可变的。 我的想法是子类Handler
和注释它作为一个消费者(即通过使用) –
trait ListHandler<in T>: Handler<List<T>> { }
然而,这给了我一个错误,说: “参数T被声明为'在',但发生在'不变'的位置Handler<List<T>
”
错误是什么意思,有什么办法可以解决它?
这个错误意味着,对于所有的编译器都知道,你的声明可能导致运行时失败。 请记住,在检查ListHandler
,编译器不知道Handler
中定义了哪些成员,它只知道Handler
已经被成功地进行了类型检查,并且它的签名表明类型参数是不变的。 这是必要的,因为Handler
可能稍后被改变并重新编译而不用重新编译ListHandler
:
trait Handler<T> { fun handle(result: T) fun get() : T }
有了这样一个声明,写一个破碎的代码很容易:
// an ill-behaved ListHandler class HandlerImpl<T> : ListHandler<T> { private var storage: List<T> = listOf() override fun handle(result: List<T>) { storage = result } override fun get(): List<T> = storage } // Code using it, that breaks fun main(args: Array<String>) { val anyHandler = HandlerImpl<Any>() anyHandler.handle(listOf(1, 2, 3)) val problematic: ListHandler<String> = anyHandler // The following line requires an element to be a String, but it is an Int problematic.get()[0].length() }
结果:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
在这里看完整的代码。