Dans Java nous pouvons le faire Events.handler(Handshake.class, hs -> out.println(hs));
En Kotlin cependant, j'essaie de reproduire le comportement pour remplacer ceci:
Events.handler(Handshake::class, object : EventHandler<Handshake> {
override fun handle(event: Handshake) {
println(event.sent)
}
})
Avec un plus pratique:
Events.handler(Handshake::class, EventHandler<Handshake> { println(it.sent) })
Pour une raison quelconque en référence à EventHandler
:
Plus préférablement cependant, j'aimerais utiliser quelque chose d'encore plus court, comme ceci: Events.handler(Handshake::class, { println(it.sent) })
Ou utilisez la fonctionnalité publiée pour utiliser la méthode comme ceci: Events.handler(Handshake::class) { println(it.sent) }
Voici mon objet Events
:
import Java.util.*
import kotlin.reflect.KClass
object Events {
private val map = HashMap<Class<*>, Set<EventHandler<*>>>()
fun <T : Any> handler(eventType: KClass<T>, handler: EventHandler<T>) {
handler(eventType.Java, handler)
}
fun <T> handler(eventType: Class<T>, handler: EventHandler<T>) = handlers(eventType).add(handler)
fun post(event: Any) = handlers(event.javaClass).forEach { it.handle(event) }
operator fun plus(event: Any) = post(event)
private fun <T> handlers(eventType: Class<T>): HashSet<EventHandler<T>> {
var set = map[eventType]
if (set == null) {
set = HashSet<EventHandler<*>>()
map.put(eventType, set)
}
return set as HashSet<EventHandler<T>>
}
}
Et mon interface EventHandler
:
@FunctionalInterface
interface EventHandler<T> {
fun handle(event: T)
}
En supposant que plus bas, vous avez vraiment besoin de EventHandler
comme interface distincte (par exemple pour Java interop). Sinon, vous pouvez simplement utiliser un alias de type (depuis Kotlin 1.1) :
typealias EventHandler<T> = (T) -> Unit
Dans ce cas, un simple lambda fonctionnera immédiatement.
Mais si vous ne voulez pas utiliser un alias de type, le problème persiste. C’est que Kotlin ne fait la conversion SAM que pour les fonctions définies en Java. Puisque Events.handler
est défini dans Kotlin, les conversions SAM ne lui sont pas applicables.
Pour supporter cette syntaxe:
Events.handler(Handshake::class, EventHandler<Handshake> { println(it.sent) })
Vous pouvez définir une fonction nommée EventHandler
:
fun <T> EventHandler(handler: (T) -> Unit): EventHandler<T>
= object : EventHandler<T> {
override fun handle(event: T) = handler(event)
}
Pour supporter cette syntaxe:
Events.handler(Handshake::class, { println(it.sent) })
ou ca:
Events.handler(Handshake::class) { println(it.sent) }
Vous devez surcharger la fonction handler
pour prendre une fonction à la place de EventHandler
:
fun <T> Events.handler(eventType: Class<T>, handler: (T) -> Unit) = EventHandler(handler)
NOTE: Quand une future version de Kotlin aura des alias de type, l'interface EventHandler
ne sera plus nécessaire, car elle sera remplacée par un alias nommé du type (T) -> Unit