问题描述
class Test11<T : Number> {
lateinit var test: MutableList<out T>.() -> Unit
}
fun main() {
val test: Test11<Int> = Test11<Int>()
val test2: Test11<out Number> = test
test.test.invoke(MutableList(3) { 55 }) // First
test2.test.invoke(MutableList(3) { 55 }) // Second
}
第二个说 MutableList<nothing>
是预期的。
所以基本上在第一种情况下,T => Int
可能是 out T => out Int => out Number
。在第二种情况下,T => out Number
是 Number 的子类,那么仍然 out T => out Number
对吗?
我无法理解为什么它不能按这种逻辑工作...
解决方法
MutableList 是一个函数参数。您会遇到完全相同的问题:
class Test11<T : Number> {
fun test(list: MutableList<out T>) {
}
}
fun main() {
val test: Test11<Number> = Test11<Number>()
val test2: Test11<out Number> = test
test.test(MutableList(3) { 55 }) // First
test2.test(MutableList(3) { 55 }) // Second
}
根据定义,协变类型可防止调用类型为参数的函数,但这在逻辑上也扩展到相同类型的嵌套协变。如果 T 是协变的(对于类),那么使用可以产生 Ts 的对象并不比直接使用 Ts 更安全。
这可能导致失败的示例:
class Test11<T : Number> {
var list: MutableList<out T>? = null
fun test(list: MutableList<out T>) {
this.list = list
}
}
fun main() {
val test: Test11<Long> = Test11()
val test2: Test11<out Number> = test
val doubleList: MutableList<out Number> = mutableListOf(1.0)
test2.test(doubleList) // Not allowed
// if it were allowed:
val long: Long? = test.list?.firstOrNull() // ClassCastException casting the Double to a Long
}