I need a function which will cast Map to Map<String, List<Int>>
Currently I use unsafe "as" but I receive a fair warning about it. I want to fix it.
For list part I was able to implement function
inline fun <reified T : Any> List<*>.checkItemsAre(): List<T> {
return this.filterIsInstance<T>().takeIf { it.size == this.size }
?: throw IllegalArgumentException("Can't convert raw List to type safe List")
}
But I can’t fund analog for map.
How can I fix it ?
>Solution :
If you are looking for something similar to the checkItemsAre for Lists that you showed, you can write such a method for Maps.
inline fun <reified K : Any, reified V: Any> Map<*, *>.checkKeyValuesAre() =
entries.associate {
Pair(
(it.key as? K) ?: throw IllegalArgumentException(),
(it.value as? V) ?: throw IllegalArgumentException()
)
}
Just like checkItemsAre, this creates a new Map if all the keys are of type K and all the values are of type V.
However, this wouldn’t completely check nested generics like Map<String, List<Int>>. If you want to handle that, you would have to add special cases for List, e.g.
return if (typeOf<V>().classifier == List::class) {
val listElemType = typeOf<V>().arguments[0].type?.classifier as KClass<*>
entries.associate {
Pair(
(it.key as? K) ?: throw IllegalArgumentException(),
(it.value as List<*>).checkItemsAre(listElemType)
)
}
} else {
// the code in the first code snippet...
}
fun <T : Any> List<*>.checkItemsAre(clazz: KClass<T>): List<T> {
return this.filterIsInstance(clazz.java).takeIf { it.size == this.size }
?: throw IllegalArgumentException()
}
If you are only going to handle maps with values of type List, I would just assume the map’s values are lists:
inline fun <reified K : Any, reified E: Any> Map<*, *>. checkKeyAndListValuesAre() =
entries.associate {
Pair(
(it.key as? K) ?: throw IllegalArgumentException(),
(it.value as List<*>).checkItemsAre<E>()
)
}