Я не знаю, как указать литерал функции, где входной параметр может коварировать, чтобы литерал функции мог назначить ему функции, которые принимают подтипы типа ввода.
Самый простой пример, который я могу придумать, – это то, что я хочу сделать что-то вроде этого:
var f: (Number) -> Unit = { number: Number -> println(number) } f = {int: Int -> println(number) } // <-- this does not compile
Эти объявления не работают:
var f: (in Number) -> Unit = {number: Number ->} // doesn't compile var f: (out Number) -> Unit = {number: Number ->} // doesn't compile var f: <N: Number> (N) -> Unit = {number: Number ->} // ridiculous
Вот контекст того, что я НАСТОЯТЕЛЬНО хочу сделать. Я хочу создать простой класс обработчика событий.
Это мой код Котлина:
class EventHandler() { private val NO_OP = {event: Event -> } private val handlerMap = mutableMapOf<KClass<out Event>, (Event) -> Unit>() // here is the problem declaration fun <E: Event> registerHandler( eventClass: KClass<out E>, handler: (E) -> Unit) { handlerMap[eventClass] = handler // this doesn't compile } fun handle(event: Event) = getHandler(event).invoke(event) fun getHandler(event: Event): (Event) -> Unit = handlerMap[event::class] ?: NO_OP }
handlerMap[eventClass] = handler
не компилируется, поскольку handlerMap
принимает значения (Event) -> Unit
, а тип handler
– (E) -> Unit
где E
– это параметр типа, который расширяет событие ( <E: Event>
).
Сообщение об ошибке:
Events.kt:[18,9] Type inference failed: Cannot infer type parameter V in operator inline fun <K, V> MutableMap<K, V>.set(key: K, value: V): Unit None of the following substitutions receiver: MutableMap<KClass<out Event>, (Event) -> Unit> arguments: (KClass<out Event>,(Event) -> Unit) receiver: MutableMap<KClass<out Event>, (E) -> Unit> arguments: (KClass<out Event>,(E) -> Unit) can be applied to receiver: MutableMap<KClass<out Event>, (Event) -> Unit> arguments: (KClass<out E>,(E) -> Unit)
Я использую kotlin-maven-plugin: 1.1-M03.
Хорошо, я не думал об этом раньше, но похоже, что вы можете просто применить функцию к типу литерала.
Другими словами, вы можете сделать это
var f: (Number) -> Unit = { number: Number -> println(number) } f = {int: Int -> println(number) } as (Number) -> Unit
Для моего фактического использования я сделал бы функцию registerHandler
следующим образом:
fun <E: Event> registerHandler(eventClass: KClass<out E>, handler: (E) -> Unit) { handlerMap[eventClass] = handler as (Event) -> Unit }