Subclassing a class 以更改 Kotlin 中类型参数的方差

Subclassing a class to change the varience of a type parameter in Kotlin

本题来源于。请在那里查看有关此问题背后动机的更多信息。

我有一个 class 接受无约束类型参数

trait Handler<T> {
    fun handle(result: T)
}

我需要创建一个 Handler 实例,其中 TList<O>,因此是不可变的。我的想法是 subclass Handler 并将其注释为消费者(即使用 in)-

trait ListHandler<in T>: Handler<List<T>> { }

但是这给了我一个错误,说 "Parameter T is declared as 'in' but occurs in 'invariant' position in 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

查看完整代码 here