为什么 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)
}
}
我希望 va
是 Array<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)
}
但是,再次使用 out
(vararg
所做的),它神奇地起作用了:
fun main() {
varargFun(arrayOf<Int>(1, 2))
}
fun varargFun(va: Array<out Number>) {
arrayFun(va)
}
以下方法在 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)
}
}
我希望 va
是 Array<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 typeT
is visible as an array ofT
, i.e. the [...] variable in the example above has typeArray<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)
}
但是,再次使用 out
(vararg
所做的),它神奇地起作用了:
fun main() {
varargFun(arrayOf<Int>(1, 2))
}
fun varargFun(va: Array<out Number>) {
arrayFun(va)
}