为什么 Kotlin 的 Type 的可变参数被视为 Array<out Type> 而不是 Array<Type>

Why Kotlin's Type's vararg is treated as Array<out Type> and not Array<Type>

以下方法在 Java 中编译:

public class Main {
    public static void main(String[] args) {
        varargMethod(1, 2.0);
    }

    static void varargMethod(Number... va) {
        arrayMethod(va);
    }

    static void arrayMethod(Number[] arr) {
        for (Number number : arr) {
            System.out.println(number);
        }
    }
}

如果我尝试在 Kotlin 中编写类似的代码,我会收到类型不匹配错误:

fun main() {
    varargFun(1, 2.0)
}

fun varargFun(vararg va: Number) {
    arrayFun(va) // Error:(6, 14) Kotlin: Type mismatch: inferred type is Array<out Number> but Array<Number> was expected
}

fun arrayFun(arr: Array<Number>) {
    arr.forEach {
        println(it)
    }
}

我希望 vaArray<String> 类型,但它是 Array<out String>。如果我施放它:va as Array<Number>,我会收到警告:

Warning:(6, 21) Kotlin: Unchecked cast: Array to Array

我该如何将 vararg 作为 Array 传递给另一个函数而不收到警告和错误?

This is covered in the Kotlin documentation:

Inside a function a vararg-parameter of type T is visible as an array of T, i.e. the [...] variable in the example above has type Array<out T>.

你的问题的解决方案很简单:忽略 Kotlin 的守卫 rails 和 .

fun varargFun(vararg va: Number) {
    val copy = arrayOf(*va)
    arrayFun(copy)
}

不同之处在于 Java 数组是协变的,即以下内容有效:

public static void main(String[] args) {
    Number[] numbers = new Number[0];
    Integer[] ints = new Integer[0];

    numbers = ints;
}

然而,数组在 Kotlin 中不是协变的,即下面给出了编译错误:

var numbers: Array<Number> = arrayOf()
val ints: Array<Int> = arrayOf()

numbers = ints // error: required Array<Number>, found Array<Int>

但是您可以使用关键字 out 声明该数组是生产者(即您保证永远不会在其中插入任何内容;编译器会确保这一点)。这使得数组协变,即以下是有效的:

var numbers: Array<out Number> = arrayOf() // we will only extract Numbers out of this array
val ints: Array<Int> = arrayOf()

numbers = ints // this is ok

鉴于此,如果 vararg va: Number 未被视为 Array<out Number>,那么您可以仅使用 Number 对象而不是其子类来调用您的方法。即,以下将失败:

fun main() {
    varargFun(arrayOf<Int>(1, 2)) // error: required Array<Number>, found Array<Int>
}

fun varargFun(va: Array<Number>) {
    arrayFun(va)
}

但是,再次使用 outvararg 所做的),它神奇地起作用了:

fun main() {
    varargFun(arrayOf<Int>(1, 2))
}

fun varargFun(va: Array<out Number>) {
    arrayFun(va)
}