【问题标题】:How does nested covariance works in Kotlin?嵌套协方差如何在 Kotlin 中工作?
【发布时间】:2021-01-12 03:35:25
【问题描述】:

在这段代码中,我很难理解为什么第一个编译而第二个不编译?

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&lt;Nothing&gt;是预期的。

所以基本上在第一种情况下,T =&gt; Int 所以可能是out T =&gt; out Int =&gt; out Number。在第二种情况下,T =&gt; out Number 是 Number 的子类,那么仍然是 out T =&gt; out Number 对吗?

我无法理解为什么它不能按照这种逻辑工作......

【问题讨论】:

    标签: kotlin generics covariance


    【解决方案1】:

    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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-05
      • 2021-08-01
      • 2012-10-31
      • 2017-09-19
      • 2019-04-30
      • 2018-06-03
      • 2022-08-18
      相关资源
      最近更新 更多