2016-12-29 2 views
0

Я не знаю, как указать литерал функции, где входной параметр может коварировать, чтобы литерал функции мог назначить ему функции, которые принимают подтипы типа ввода.Объявление функциональных литералов с общими входными параметрами в Kotlin

Простейший пример, который я могу придумать, что я хочу сделать что-то вроде этого:

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) 

Я использую Котлин-Maven-плагин: 1,1-M03.

+0

Это должно работать вне коробки , без вас, объявляя 'in' или' out' и без кастинга. В противном случае вы делаете что-то неправильно, и он может выйти из строя во время выполнения. – voddan

+0

Возможный дубликат [Ввод общей лямбды в карту] (http://stackoverflow.com/questions/35973872/putting-a-generic-lambda-into-a-map) – Ilya

ответ

1

Хорошо, я не думал об этом раньше, но похоже, что вы можете просто передать функцию в тип литерала.

Другими словами, вы можете сделать это

var f: (Number) -> Unit = { number: Number -> println(number) } 
f = {int: Int -> println(number) } as (Number) -> Unit 

Для моего фактического USECASE, я хотел бы сделать registerHandler функцию выглядеть следующим образом:

fun <E: Event> registerHandler(eventClass: KClass<out E>, handler: (E) -> Unit) { 
    handlerMap[eventClass] = handler as (Event) -> Unit 
} 
Смежные вопросы