Reputation: 877
A function toArray
should convert type-erased list to T
that is Array<String>
now.
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")
However, toArray
throws this error.
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
Do you have any ideas?
Upvotes: 30
Views: 46940
Reputation: 31274
To understand why this happens I recommend reading Difference between List and Array types in Kotlin and Java Practices -> Prefer Collections over older classes.
In general I recommend using lists instead of arrays but if you want to convert a type-erased list to an array in Kotlin the easiest way to do so is first mapping to a typed list and then converting to a typed array:
list.map { it as String }.toTypedArray()
If you don't actually need an array but a typed list will do then you can simply map the type-erased list to a typed list:
list.map { it as String }
If you find yourself often converting a type-erased list to an array and performance matters then I recommend creating a map function optimized for doing this while avoiding an intermediary list:
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()) } }
}
}
You can then efficiently convert a List<*>
to a typed array:
list.mapToTypedArray { it as String }
Upvotes: 14
Reputation: 6819
For some reason, I was getting an invalid argument number exception when I was trying to do this:
val argumentTypeMirrors = mutableListOf<TypeMirror>()
... // add items to argumentTypeMirrors
val array = argumentTypeMirrors.toTypedArray()
And I ended up doing it this way:
val argumentTypeMirrors = mutableListOf<TypeMirror>()
... // add items to argumentTypeMirrors
val array = Array(argumentTypeMirrors.size) {
argumentTypeMirrors[it]
}
Then I was able to destruct my array
with *array
for passing it as a varargs
parameter.
Upvotes: 1
Reputation: 14640
Problem here, is that you actually trying cast Object[]
to String[]
in terms of Java, or Array<Any>
to Array<String>
in terms of Kotlin, but this is different objects.
So, this statement:
list.toTypedArray()
returns Array<Any?>
, and then you trying to cast it to Array<String>
and get ClassCastException
.
I suggest pass type parameter itself, and cast List
:
inline fun <reified T> toArray(list: List<*>): Array<T> {
return (list as List<T>).toTypedArray()
}
toArray<String>(listOf("1", "2"))
Upvotes: 61