В Kotlin я могу использовать filterIsInstance
для получения подгруппы, зависящей от типа (и безопасной для типов):
val misc: List<Any> = listOf(42, 3.14, true, "foo", "bar")
val strings: List<String> = misc.filterIsInstance<String>()
println(strings) // => [foo, bar]
Но у меня есть большая коллекция объектов, и я хотел бы предварительно отсортировать ее в карту по конкретному типу. Можно ли вообще определить такую карту в системе типов Котлина?
val miscByType: Map<KType, Collection<???>>
или
val miscByClass: Map<KClass, Collection<???>>
Должен ли я использовать пользовательскую реализацию с небезопасным (но логически обоснованным) приведением?
Ниже приведена такая реализация. Это работает, но мне интересно, есть ли менее хакерский способ сделать это:
import kotlin.reflect.KClass
class InstanceMap {
// INVARIANT: map from KClass to a set of objects of *that concrete class*
private val map: MutableMap<KClass<*>, MutableSet<Any>> = mutableMapOf()
// this is the only public mutator, it guarantees the invariant
fun add(item: Any): Boolean =
map.getOrPut(item::class) { mutableSetOf() }.add(item)
// public non-inline accessor, only needed by the inline accessor
fun get(cls: KClass<*>): Set<*>? = map[cls]
// inline accessor that performs an unsafe, but sound, cast
@Suppress("UNCHECKED_CAST")
inline fun <reified T> get(): Set<T> = get(T::class) as Set<T>? ?: setOf()
}
fun instanceMapOf(vararg items: Any): InstanceMap = InstanceMap().apply {
items.forEach { add(it) }
}
val misc = instanceMapOf(42, 3.14, true, "foo", "bar")
val strings = misc.get<String>()
println(strings) // => [foo, bar]