如何将函数引用保存为Map类型的值,然后在Kotlin中用参数调用它?
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中完成。 任何帮助将受到欢迎。 谢谢!
正确的语法是"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()
,则更改主体以测试Int
和String
,并将整数转换为字符串。
当你写{ asParam1() }
,你创建一个带有可执行代码块的lambda,所以你需要正确地调用函数asParam1(...)
,这需要一个Int
参数。
所以,你需要做的第一个改变是: { i -> asParam1(i) }
。
但是这段代码仍然没有通过类型检查,因为匹配地图的类型,lambda将被输入为(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的答案中一样 。