使用Kotlin中的单个泛型组合不同的参数类型

时间:2019-03-29 12:57:42

标签: generics 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 个答案:

答案 0 :(得分:1)

(KClass<*>) -> Unit表示采用 KClass <*>作为参数的函数类型。 lambda后面有隐藏的功能接口。更好的选择是引入自己的界面,例如

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
    }
}

为简化示例,可以用通用lambda函数Callback替换(Any) -> Unit接口。实际上,在界面中包含其他内容可能很有意义,所以很可能仍然有意义