2016-12-29 56 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) 

我使用科特林-行家-插件:1.1-M03。

+0

這應該工作外的開箱,沒有你聲明'in'或'out',並且沒有投射。否則,你做錯了事,它可能會在運行時失敗。 – voddan

+0

[把普通的lambda放到地圖中]可能的重複(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 

對於我的實際用例,我會做一下registerHandler功能是這樣的:

​​
相關問題