以下方法使用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>
,则会收到警告:
警告:(6,21)Kotlin:未经检查的演员表:从阵列到阵列
我应该如何将vararg
作为Array
传递给另一个函数,而又不会收到警告和错误?
答案 0 :(得分:5)
区别在于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))
}
fun varargFun(va: Array<Number>) {
arrayFun(va)
}
但是再次使用out
(vararg
就是这样做的),它神奇地起作用了:
fun main() {
varargFun(arrayOf<Int>(1, 2)) // error: required Array<Number>, found Array<Int>
}
fun varargFun(va: Array<out Number>) {
arrayFun(va)
}
答案 1 :(得分:1)
This is covered in the Kotlin documentation:
在函数内部,类型为
let escapeString = unescapeString.replace(/([<>*()?])/g, "\\$1")
的{{1}}参数作为vararg
的数组可见,即,上面示例中的[...]变量的类型为{{1 }}。
解决问题的方法很简单:忽略Kotlin的护栏和copy the arguments。
T