Объедините различные типы параметров, используя один общий в Kotlin - PullRequest
0 голосов
/ 29 марта 2019

Допустим, у нас есть следующие переменные:

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 Ответ

1 голос
/ 29 марта 2019

(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. На практике, возможно, имеет смысл включить что-то еще в интерфейс, так что, вероятно, все еще имеет смысл

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...