如何在Kotlin中将类型擦除列表转换为数组?

mmo*_*iro 16 arrays list kotlin

函数toArray应该将类型擦除列表转换TArray<String>现在的列表.

inline fun <reified T> toArray(list: List<*>): T {
    return list.toTypedArray() as T
}

toArray<Array<String>>(listOf("a", "b", "c")) // should be arrayOf("a", "b", "c")
Run Code Online (Sandbox Code Playgroud)

但是,toArray抛出此错误.

java.lang.ClassCastException:[Ljava.lang.Object; 无法转换为[Ljava.lang.String;

你有什么想法?

Rus*_*lan 42

这里的问题是,你实际上是试图投Object[]String[]Java中的条款,或者Array<Any>Array<String>在科特林方面,但这是不同的对象.

所以,这句话:

list.toTypedArray()
Run Code Online (Sandbox Code Playgroud)

返回Array<Any?>,然后你试图把它投射到Array<String>并得到ClassCastException.

怎么修?

我建议传递类型参数本身,并强制转换List:

inline fun <reified T> toArray(list: List<*>): Array<T> {
    return (list as List<T>).toTypedArray()
}

toArray<String>(listOf("1", "2"))
Run Code Online (Sandbox Code Playgroud)


mfu*_*n26 8

要了解为什么会发生这种情况,我建议阅读KotlinJava 实践中列表和数组类型之间的差异-> 首选集合而不是旧类

一般来说,我建议使用列表而不是数组,但如果您想在 Kotlin 中将类型擦除列表转换为数组,最简单的方法是首先映射到类型列表,然后转换为类型数组:

list.map { it as String }.toTypedArray()
Run Code Online (Sandbox Code Playgroud)

如果您实际上不需要数组但类型列表可以,那么您可以简单地将类型擦除列表映射到类型列表:

list.map { it as String }
Run Code Online (Sandbox Code Playgroud)

如果您发现自己经常将类型擦除列表转换为数组并且性能很重要,那么我建议创建一个为此优化的映射函数,同时避免中间列表:

inline fun <T, reified R> List<T>.mapToTypedArray(transform: (T) -> R): Array<R> {
    return when (this) {
        is RandomAccess -> Array(size) { index -> transform(this[index]) }
        else -> with(iterator()) { Array(size) { transform(next()) } }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以有效地将 a 转换List<*>为类型化数组:

list.mapToTypedArray { it as String }
Run Code Online (Sandbox Code Playgroud)