#generics #kotlin
#универсальные параметры #kotlin
Вопрос:
Допустим, у нас есть следующие переменные:
private val subscriptions1 = ArrayList<(String) -> Unit>()
private val subscriptions2 = ArrayList<(Int) -> Unit>()
private val subscriptions3 = ArrayList<(Char) -> Unit>()
Возможно ли объединить их в одну карту следующим образом?
private val subscriptions = ConcurrentHashMap<KClass<*>, ArrayList<(KClass<*>) -> Unit>>()
Следующий код не компилируется с переменной subscriptions
, как я определил это выше:
inline fun <reified T : Any> send(event: T) {
val eventSubscriptions = getSubscriptionsOnEvent(T::class)
for (eventProcessor in eventSubscriptions) {
eventProcessor(event)
}
}
Ответ №1:
(KClass<*>) -> Unit
Означает тип функции, которая принимает KClass<*> в качестве параметра. За лямбдами скрываются функциональные интерфейсы. Лучшей альтернативой является внедрение вашего собственного интерфейса, например
interface Callback {
operator fun fun invoke(t: Any) : Unit //operator for better syntax
}
val subscriptions = ConcurrentHashMap<KClass<*>, List<Callback>>()
fun <reified T> subscribe<T>(action: (T) -> Unit) {
val wrapper = object: Callback {
override operator fun invoke(t: Any) {
action(t as T) ///inline function allows the cast
}
}
subscriptions[T::class] = (subscriptions[T::class] ?: listOf<Callback>()) wrapper
}
//works as-is
inline fun <reified T : Any> send(event: T) {
val eventSubscriptions = getSubscriptionsOnEvent(T::class)
for (eventProcessor in eventSubscriptions) {
eventProcessor(event) /// Callback.invoke function is called implicitly
}
}
Чтобы сократить пример, можно заменить Callback
интерфейс универсальной лямбда-функцией (Any) -> Unit
. На практике, возможно, имеет смысл включить что-то еще в интерфейс, так что, вероятно, это все еще имеет смысл
Комментарии:
1. Это интересно. Я буду использовать это как решение. Спасибо!