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()
}
我的要求很简单,我想将函数 asParam1
和 asParam2
保存为变量 specials
中的值 . 稍后通过从 Map
获取值来调用它 .
但是,编译器不喜欢它:
错误:(1,40)类型推断失败 . 预期的类型不匹配:推断的类型是Map Unit>但是Map Unit>是预期的错误:(1,69)没有为参数num传递值错误:(1,96)没有为参数文本传递值
虽然这个任务在弱类型语言中非常简单,但我不知道如何在Kotlin中做 . 欢迎任何帮助 . 谢谢!
2 回答
正确的语法是
"calllme" to ::asParam1
.但是签名将是错误的,因为
Map
期望类型为(Any)->Unit
,而您的(Int)->Unit
和(String)->Unit
. 这是一个不产生错误的示例:请记住,调用者的代码具有关于如何调用每个函数(即正确的参数类型)的特殊知识,但编译器没有相同的知识 . 您可能会不小心调用
asParam1
传递String
而不是Int
(这是您的caller
函数正在执行的操作,我在我的示例中修复了它)并且这是不允许的 . 这就是为什么我将asParam*
的签名更改为接受Any
参数,然后验证每个函数中的预期类型(忽略不良类型) .如果您的意图 is 除了字符串之外还要将整数传递给
asParam2()
,那么更改正文以测试Int
和String
并将整数转换为字符串 .当您编写
{ asParam1() }
时,您在其中创建一个带有可执行代码块的lambda,因此您需要正确调用函数asParam1(...)
,这需要Int
参数 .因此,您需要做的第一个更改是:
{ i -> asParam1(i) }
.但是这段代码仍然没有通过类型检查,因为匹配 Map 的类型,lambda将被输入为
(Any) -> Unit
( Map 中的值应该都能够接受Any
,并且期望更窄类型的函数不能是这张 Map 中的一个值) .然后,您需要将
Any
参数转换为Int
才能调用该函数:{ i -> asParam1(i as Int) }
最后, Map 将如下所示:
调用保持不变,如代码示例中所示 .
函数引用语法(
::asParam1
)允许您引用已接受Any
的函数,它不会隐式进行上述转换 . 要使用它,您必须修改函数以接受Any
,如@Les's answer .