如何将函数引用保存为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() } 

我的要求很简单,我想保存函数asParam1asParam2作为一个值在变量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() ,则更改主体以测试IntString ,并将整数转换为字符串。

当你写{ 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的答案中一样 。