2017-08-03 56 views
2
val specials:Map<String, (Any)->Unit> = mapOf(
     "callMe1" to {asParam1()}, 
     "callMe2" to {asParam2()} 
) 

fun asParam1(num:Int) { 
    println(num) 
} 

fun asParam2(text:String) { 
    println(text) 
} 

fun caller() { 
    specials["callMe1"]?.invoke("print me") 
    specials["callMe2"]?.invoke(123) 
} 


fun main(args: Array<String>) { 
    caller() 
} 

我的要求很簡單,我想功能asParam1asParam2保存爲變量specials的值。稍後通過從Map獲取值來調用它。如何將函數引用保存爲Map類型的值,並在Kotlin中稍後使用參數調用它?

但是,編譯器不喜歡它:

Error:(1, 40) Type inference failed. Expected type mismatch: inferred type is Map Unit> but Map Unit> was expected
Error:(1, 69) No value passed for parameter num
Error:(1, 96) No value passed for parameter text

這個任務是弱類型語言很簡單,我不知道如何在科特林做。任何幫助將受到歡迎。謝謝!

+0

如果你的'Map'沒有改變,使用'when'也是可以的。 – BakaWaii

回答

1

正確的語法是"calllme" to ::asParam1

但是然後簽名將是錯誤的,因爲Map預計類型(Any)->Unit和您的有(Int)->Unit(String)->Unit。這裏是不會產生錯誤的例子:

val specials:Map<String, (Any)->Unit> = mapOf(
     "callMe1" to ::asParam1, 
     "callMe2" to ::asParam2 
) 

fun asParam1(num:Any) { 
    if(num is Int) println(num) 
} 

fun asParam2(text:Any) { 
    if(text is String) println(text) 
} 

fun caller() { 
    specials["callMe2"]?.invoke("print me") 
    specials["callMe1"]?.invoke(123) 
} 

請記住,您的來電代碼在如何調用每個函數(即正確的參數類型)的專業知識,但是編譯器沒有這個知識。您可能會不小心撥打asParam1,而不是通過String而不是Int(這是您的caller函數正在做的事情,我將其固定在我的示例中),這是不允許的。這就是爲什麼我將asParam*的簽名更改爲接受Any參數,然後驗證每個函數中的預期類型(忽略錯誤類型)。

如果你的目的是除了傳遞整數字符串asParam2(),然後換身來測試這兩個IntString和整數轉換爲字符串。

+0

進一步注意:如果'asParam *()'是一個類的方法,語法會改變一點,你會寫'this :: asParam1'而不是':: asParam1' – Les

+0

謝謝你的注意,現在所有的作品。是的,真正的案例是在課堂上:) –

1

當你寫{ asParam1() },爲您打造,內帶一個可執行代碼塊拉姆達,所以你需要正確地調用該函數asParam1(...),這需要一個Int說法。

因此,您需要進行的第一項更改爲:{ i -> asParam1(i) }

但這個代碼仍然將不能通過類型檢查,因爲匹配的地圖類型,拉姆達將分型爲(Any) -> Unit(在圖中的值都應該能夠接受Any,並且期望一個函數更窄的類型不能成爲該地圖中的值)。

然後,您需要到Any參數轉換爲Int才能夠調用該函數:
{ i -> asParam1(i as Int) }

最後,地圖上看起來是這樣:

val specials: Map<String, (Any) -> Unit> = mapOf(
    "callMe1" to { i -> asParam1(i as Int) }, 
    "callMe2" to { s -> asParam2(s as String) } 
) 

調用保持不變,在你的代碼示例中。

函數參考語法(::asParam1)將允許您引用已接受Any的函數,它不會隱式地進行上述轉換。要使用它,你必須修改你的函數來接受Any,如@Les's answer

相關問題