为什么Kotlin的Type的vararg被视为Array <out Type>而不是Array <Type>

Kir*_*ill 5 generics variadic-functions kotlin

以下方法使用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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试在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)
    }
}
Run Code Online (Sandbox Code Playgroud)

我期望va是这样的Array<String>,但是是Array<out String>。如果将其强制转换为:va as Array<Number>,则会收到警告:

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

How am I supposed to pass vararg as an Array to another function without getting warning and errors?

use*_*612 6

The difference is that in Java arrays are covariant, i.e. the following is valid:

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

    numbers = ints;
}
Run Code Online (Sandbox Code Playgroud)

However, arrays are not covariant in Kotlin, i.e. the following gives a compilation error:

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

numbers = ints // error: required Array<Number>, found Array<Int>
Run Code Online (Sandbox Code Playgroud)

但是,您可以使用关键字声明数组是一个生产器(即,您保证不会在其中插入任何内容;编译器将确保这样做)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
Run Code Online (Sandbox Code Playgroud)

鉴于此,如果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)
}
Run Code Online (Sandbox Code Playgroud)

但同样,有一个out(这是vararg做),它神奇地运行:

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

fun varargFun(va: Array<out Number>) {
    arrayFun(va)
}
Run Code Online (Sandbox Code Playgroud)


ord*_*lex 5

Kotlin 文档对此进行了介绍

在函数内部,vararg类型的参数T作为 的数组可见T,即上面示例中的 [...] 变量具有类型Array<out T>

问题的解决方案很简单:忽略 Kotlin 的护栏,并复制 arguments

fun varargFun(vararg va: Number) {
    val copy = arrayOf(*va)
    arrayFun(copy)
}
Run Code Online (Sandbox Code Playgroud)