web-dev-qa-db-ja.com

Kotlin:機能的インターフェースの代わりにラムダを使用しますか?

Javaこれを行うことができますEvents.handler(Handshake.class, hs -> out.println(hs));

しかし、Kotlinではこれを置き換えるために動作を複製しようとしています:

_Events.handler(Handshake::class, object : EventHandler<Handshake> {
    override fun handle(event: Handshake) {
        println(event.sent)
    }
})
_

より便利に:

Events.handler(Handshake::class, EventHandler<Handshake> { println(it.sent) })

EventHandlerを参照する何らかの理由で:

enter image description here

しかし、より好ましくは、このようなさらに短いものを使用したいと思います:Events.handler(Handshake::class, { println(it.sent) })

または、アドバタイズされた機能を使用して、次のようなメソッドを使用します:Events.handler(Handshake::class) { println(it.sent) }

これは私の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>>
    }

}
_

そして、私のEventHandlerインターフェース:

_@FunctionalInterface
interface EventHandler<T> {

    fun handle(event: T)

}
_
42
Jire

以下では、EventHandlerが個別のインターフェイスとして本当に必要であると仮定します(例:Java interop)。必要ない場合は、単にタイプエイリアスを使用できます(Kotlin 1.1以降) :

typealias EventHandler<T> = (T) -> Unit

この場合、単純なラムダがすぐに機能します。

ただし、タイプエイリアスを使用したくない場合は、問題が解決しません。 KotlinはJavaで定義された関数に対してのみSAM変換を行うということです。 Events.handlerはKotlinで定義されているため、SAM変換は適用されません。

この構文をサポートするには:

Events.handler(Handshake::class, EventHandler<Handshake> { println(it.sent) })

EventHandlerという名前の関数を定義できます:

fun <T> EventHandler(handler: (T) -> Unit): EventHandler<T> 
    = object : EventHandler<T> { 
        override fun handle(event: T) = handler(event) 
    }

この構文をサポートするには:

Events.handler(Handshake::class, { println(it.sent) })

またはこれ:

Events.handler(Handshake::class) { println(it.sent) }

handlerの代わりに関数を使用するには、EventHandler関数をオーバーロードする必要があります。

fun <T> Events.handler(eventType: Class<T>, handler: (T) -> Unit) = EventHandler(handler)

注:Kotlinの将来のバージョンに型エイリアスがある場合、EventHandlerインターフェイスは、(T) -> Unit型の名前付きエイリアスに置き換えられるため、必要ありません。

67
Andrey Breslav