首页 文章

如何将函数引用保存为Map类型中的值,并稍后在Kotlin中使用参数调用它?

提问于
浏览
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 获取值来调用它 .

但是,编译器不喜欢它:

错误:(1,40)类型推断失败 . 预期的类型不匹配:推断的类型是Map Unit>但是Map Unit>是预期的错误:(1,69)没有为参数num传递值错误:(1,96)没有为参数文本传递值

虽然这个任务在弱类型语言中非常简单,但我不知道如何在Kotlin中做 . 欢迎任何帮助 . 谢谢!

2 回答

  • 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 参数,然后验证每个函数中的预期类型(忽略不良类型) .

    如果您的意图 is 除了字符串之外还要将整数传递给 asParam2() ,那么更改正文以测试 IntString 并将整数转换为字符串 .

  • 1

    当您编写 { asParam1() } 时,您在其中创建一个带有可执行代码块的lambda,因此您需要正确调用函数 asParam1(...) ,这需要 Int 参数 .

    因此,您需要做的第一个更改是: { i -> asParam1(i) } .

    但是这段代码仍然没有通过类型检查,因为匹配 Map 的类型,lambda将被输入为 (Any) -> Unit ( Map 中的值应该都能够接受 Any ,并且期望更窄类型的函数不能是这张 Map 中的一个值) .

    然后,您需要将 Any 参数转换为 Int 才能调用该函数:
    { i -> asParam1(i as Int) }

    最后, Map 将如下所示:

    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 .

相关问题