这是我为了理解Kotlin 语言而刻意举的一个例子. 下面的类Box<T>对包含相同类型T的框的框进行建模.

问题是为什么arr += x会导致编译错误,而arr.add(x)不会. 错误消息为:

类型不匹配.必需:kotlin.collections.ArrayList Box>

找到:List&lt;Box&gt;

属性arr是不可变的并且指向可变列表.因此,我相信arr += x应该是arr = arr + x还是arr.add(x)是没有歧义的.应该是arr.add(x)的意思

我还注意到,如果泛型类型Box实现Iterable<T>而不是Iterable<Box<T>>,这个问题就解决了

那么,错误的原因是什么呢?


class Box<T>(private val arr: ArrayList<Box<T>> = ArrayList()) : Iterable<Box<T>> {
    private val id: Int = seq++

    override operator fun iterator(): Iterator<Box<T>> {
        return object : Iterator<Box<T>> { 
            private var i = 0;
            override fun hasNext(): Boolean {
                return i < arr.size
            }

            override fun next(): Box<T> {
                return arr[i++]
            }
        }
    }

    fun add(x: Box<T>) {
        // arr.add(x) // OK 
        arr += x // Error: Type mismatch.
    }

    companion object {
        var seq: Int = 0
    }

    override fun toString(): String {
        return "Box[$id]"
    }
}

fun main() {
    val box = Box<Int>(arrayListOf(Box(), Box()))
    for (x in box) {
        println(x)
    }
}

推荐答案

arr += x既不是arr = arr + x(尽管在其他情况下可能是),也不是arr.add(x)(至少不是directly).这只是对plusAssign操作符函数的调用.

有许多plusAssign的重载.与这条问题有关的问题如下:

operator fun <T> MutableCollection<in T>.plusAssign(
    element: T)

operator fun <T> MutableCollection<in T>.plusAssign(
    elements: Iterable<T>)

第一个重载将调用arr.add(x),第二个重载将调用arr.addAll(x).

问题是,both of these个适用于您的情况,但其中没有"最具体"的重载.

第一个重载是普通适用的,第二个重载是适用的,因为x也是Iterable<Box<T>>,因为接口实现.

这些都不是更具体的,因为它们都不能将呼叫"转发"给另一个.如果一个重载可以"转发"到所有其他适用的重载,则重载是最具体的.在本例中:

fun <T> MutableCollection<T>.plusAssign1(x: T) {
    this.plusAssign2(x) // does not compile
}
fun <T> MutableCollection<T>.plusAssign2(x: Iterable<T>) {
    this.plusAssign1(x) // also does not compile
}

另请参阅Kotlin Language Specification.

我只会手动呼叫add来修复错误,而不是使用操作符.

Kotlin相关问答推荐

如何将时间值格式化为00:00和00:00:00 Kotlin?""""

判断字符串是否除了.&" ",","@""""

解决Microronaut中多个可能的Bean候选者冲突

如何让Gradle8+在编译Kotlin代码之前编译Groovy代码?然后把它们混合在一个项目中?

Kotlin:类型不匹配:推断的类型已运行,但应等待

S使用MAP和ElseThrow的习惯用法是什么?

MyType.()在 Kotlin 中是什么意思?

将 java Optional 转换为 Kotlin Arrow Option

kotlin 父类具有依赖于抽象变量的变量

如何在 Android Jetpack Compose 中的画布上绘制一侧加厚的描边?

如何在 kotlin 中使用带有泛型的密封类

如何在 jOOQ 中两次加入同一张表?

在 kotlin 中重载函数时,我在一些非常基本的代码上不断收到类型不匹配

Kotlin 具体类从抽象类和接口扩展而来,接口使用抽象类中实现的方法

AIDL 中的 Parcelize 注释:Incompatible types: Object cannot be converted to MyCustomObject

Gradle 同步失败:不支持的方法:KotlinPlatformContainer.supports()

从代码块执行和返回(在 Elvis 运算符之后)

Kotlin协程无法处理异常

不推荐使用仅限生命周期的LifecycleEvent

Kotlin for assertThat(foo, instanceOf(Bar.class))