如何在构造函数调用中引用实例方法



我正在Kotlin中编写一些基于协程的事件处理代码,进展顺利。我在各种事件处理程序中都有做同样事情的代码,我正试图将这些代码放在一个地方。我陷入了以下困境。其思想是,子类可以通过提供类到方法的映射来指定可以处理的事件类型。不过我无法编译它。有没有办法做到这一点?有更好的方法吗?谢谢


abstract class EventHandler(private val handlers: Map<KClass<out Event>, suspend (Event) -> Unit>) {
suspend fun handle(event: Event) {
val handler = handlers[event::class]
if (handler != null) {
handler(event)
} else {
throw IllegalStateException("No handler configured for $event")
}
}
}
data class ExampleEvent(private val id: String): Event
class ExampleHandler(): EventHandler(mapOf(ExampleEvent::class to handleExample)) {
^^^^^^^^^^^^^ - compile error
suspend fun handleExample(event: ExampleEvent) {
TODO()
}
}

由于三个不同的原因,您无法编译它:

  1. 由于handleExample是一个实例方法,您不能在超级构造函数中引用它,因为您的子类的实例还没有创建。

  2. 如果你想要一个实例方法的函数引用,你应该在它前面加上::,所以在你的例子中是::handleExample

  3. 函数handleExample接受类型为ExampleEvent的事件,因此它不符合输入类型Event,在这种情况下,您需要强制转换。

也就是说,你的问题有一个解决方案,它解决了上面的3点,以及为每个EventHandler子类重复该样板的负担。

解释全在评论上。

inline fun <reified T : Event> typedCoroutine(crossinline block: suspend (T) -> Unit): Pair<KClass<out Event>, suspend (Event) -> Unit> =
// Since the type is reified, we can access its class.
// The suspend function calls the required suspend function casting its input.
// The pair between the two is returned.
T::class to { event -> block(event as T) }
abstract class EventHandler {
// Require the subclasses to implement the handlers.
protected abstract val handlers: Map<KClass<out Event>, suspend (Event) -> Unit>
suspend fun handle(event: Event) {
val handler = handlers[event::class]
if (handler != null) {
handler(event)
} else {
throw IllegalStateException("No handler configured for $event")
}
}
}
class ExampleHandler : EventHandler() {
// The type of typedCoroutine is inferred from handleExample.
override val handlers: Map<KClass<out Event>, suspend (Event) -> Unit> = mapOf(typedCoroutine(::handleExample))
suspend fun handleExample(event: ExampleEvent) {
TODO()
}
}

使用typedCoroutine,您可以在所有EventHandler子类中轻松地填充handlers映射。

最新更新