为什么传递原始vararg参数时Kotlin传播运算符需要toTypedArray()?

时间:2018-07-30 18:29:02

标签: generics kotlin rx-java

我有一个100%用Kotlin编写的Android应用。

在单元测试课中,我有2个测试观察者,一个观察整数,另一个观察对象:

val conversationCountObserver: TestObserver<Int>
val conversationObserver: TestObserver<Conversation>

对于每一个我想做一些基本的断言,例如检查是否没有错误并检查观察到的值。我决定编写一种通用方法,该方法可以对RX TestObserver类中的元素列表执行许多断言,并编写2种代理方法,以通过Kotlin *散布运算符传递值的相应观察者和变量:

private fun thenConversationsNotified(vararg conversations: Conversation) {
    thenTestObserverNotified(conversationObserver, *conversations)
}

private fun thenConversationCountNotified(vararg counts: Int) {
    thenTestObserverNotified(conversationCountObserver, *counts)
}

private fun <T>thenTestObserverNotified(observer: TestObserver<T>, vararg elements: T) {
    observer.assertNoErrors()
    elements.forEachIndexed { index, element ->
        observer.assertValueAt(index, element)
    }
}

thenConversationsNotified()方法工作正常,但是thenConversationCountNotified()显示错误:

enter image description here

enter image description here

在阅读Kotlin文档(http://kotlinlang.org/docs/reference/java-interop.html#java-arrays)之后,我意识到原始类型的vararg实际上创建了一个IntArray对象而不是一个Array,这是Java互操作的一种解决方案,该方法将原始变量与对象不同地对待。所以我必须用.toTypedArray()重写thenConversationCountNotified:

private fun thenConversationCountNotified(vararg counts: Int) {
    thenTestObserverNotified(conversationCountObserver, *counts.toTypedArray())
}

为什么散布运算符不能以与对象数组相同的方式在原始数组类上工作?有什么方法可以在这里删除对.toTypedArray()的调用?

P.S。请注意,在上面的链接中,它们声明了返回IntArray的intArrayOf(1,2,3),并且在将其传递给其他方法时,散布运算符可以正常工作。因此,传播算子确实适用于IntArray类。 Kotlin文档中的示例与我的方法之间的唯一区别是,我在一个方法中有2个参数,一个是具体参数,而一个是vararg。

1 个答案:

答案 0 :(得分:4)

如果将Int类型用作类型参数(在您的情况下,将替换T),则不能使用JVM原语,这是JVM的限制(它具有一个带有{{ 1}}代替type参数,因此它不能接受基元。

java.lang.Object使情况复杂化,但是在幕后,接受vararg的功能与接受vararg elements: T的功能相同。

因此,您需要传递Array<T>(装箱整数数组)而不是Array<Int>(原语数组),并且IntArray函数是获取前者的方法。