Kotlin 如何将字符串映射到函数并稍后调用它

Kotlin 如何将字符串映射到函数并稍后调用它,kotlin,lambda,Kotlin,Lambda,我是Kotlin的新手,我尝试在动态类型语言(如Python和JavaScript)中实现的是非常简单的,但在Kotlin中没有这么简单。我有一组接受消息对象的消息处理函数。每个消息类实现消息接口。我想将每个消息处理程序函数映射到一个字符串键: interface Message data class TestMessage1(val body: String): Message data class TestMessage2(val body: String): Message fun t

我是Kotlin的新手,我尝试在动态类型语言(如Python和JavaScript)中实现的是非常简单的,但在Kotlin中没有这么简单。我有一组接受消息对象的消息处理函数。每个消息类实现
消息
接口。我想将每个消息处理程序函数映射到一个
字符串
键:

interface Message

data class TestMessage1(val body: String): Message
data class TestMessage2(val body: String): Message

fun testMessage1Handler(msg: TestMessage1) { println(msg.body) }
fun testMessage2Handler(msg: TestMessage2) { println(msg.body) }

val functions = mapOf<String, (Message)->Unit> (
        "testMessage1" to ::testMessage1Handler,
        "testMessage2" to ::testMessage2Handler
)
接口消息
数据类TestMessage1(val正文:字符串):消息
数据类TestMessage2(val正文:String):消息
有趣的testMessage1Handler(msg:TestMessage1){println(msg.body)}
有趣的testMessage2Handler(msg:TestMessage2){println(msg.body)}
val函数=mapOfUnit>(
“testMessage1”到::testMessage1Handler,
“testMessage2”到::testMessage2Handler
)
这段代码给了我两个错误:

error: type inference failed.
Expected type mismatch: inferred type is
Pair<String, KFunction1<@ParameterName Line_1.TestMessage1, Unit>>
but
Pair<String, (Line_1.Message) -> Unit> was expected

error: type inference failed.
Expected type mismatch: inferred type is 
Pair<String, KFunction1<@ParameterName Line_1.TestMessage2, Unit>>
but
Pair<String, (Line_1.Message) -> Unit> was expected
错误:类型推断失败。
预期类型不匹配:推断类型为
一对
但是
应为配对单位>
错误:类型推断失败。
预期类型不匹配:推断类型为
一对
但是
应为配对单位>
为什么我不能使用接口
消息
作为函数类型参数?因为
TestMessage1
TestMessage2
都实现了这个接口,所以我觉得它是正确的。您将如何实现这样的功能


有一个相关的问题,但我不想将消息处理程序参数
msg
类型更改为
Any

,下面的代码进行编译,但使问题变得毫无意义

类型参数现在匹配。或许泛型也可以应用,但我不知道如何应用

interface Message {
    val body: String
}

data class TestMessage1(override val body: String): Message
data class TestMessage2(override val body: String): Message

fun messageHandler(msg: Message) { println(msg.body) }

val functions = mapOf<String, (Message)->Unit> (
        "testMessage1" to ::messageHandler,
        "testMessage2" to ::messageHandler
)
接口消息{
val body:String
}
数据类TestMessage1(覆盖val正文:字符串):消息
数据类TestMessage2(覆盖val正文:字符串):消息
FunMessageHandler(msg:Message){println(msg.body)}
val函数=mapOfUnit>(
“testMessage1”到::messageHandler,
“testMessage2”到::messageHandler
)

让我们从另一个角度来看

如果我们没有尝试并未能指定类型,而是让Kotlin有机会通过指定不正确的类型来推断它,该怎么办

val functions: String = mapOf(
    "testMessage1" to ::testMessage1Handler,
    "testMessage2" to ::testMessage2Handler
)
这将产生:

inferred type is Map<String, KFunction1<*, Unit>> but String was expected.
明白了吗

Type mismatch.
Required: Nothing
Found: TestMessage1
请注意,Kotlin推断您的输入类型为
Nothing

为了了解原因,让我们只看一个函数:

fun testMessage1Handler(msg: TestMessage1)
并扪心自问:除了
TestMessage1
这个函数还可以接收什么类型的消息?没有其他类型。它无法接收TestMessage2。它无法接收
消息
,因为
消息
不一定是
TestMessage1


对于第二个函数,我们将得到相同的答案。因此,两者的共同类型是
Nothing
。这使得这个抽象从一开始就不是很有用。

为什么我不能使用接口消息作为函数类型参数:因为如果您尝试使用消息作为参数调用testMessage1Handler,则不会编译:testMessage1Handler只接受TestMessage1的实例,而不是消息的任何实例。您首先需要检查消息是否是TestMessage1的实例并强制转换它。如果它不是TestMessage1,那又怎样?还值得指出的是,虽然可以按名称引用函数,但在静态类型语言中这不是一个好的实践,而且几乎不需要。(一方面,它击败了一些自动重构。)也许如果你解释一下你最终想要实现的目标,有人会提出更好的方法?
functions["testMessage1"]?.invoke(TestMessage1("a"))
Type mismatch.
Required: Nothing
Found: TestMessage1
fun testMessage1Handler(msg: TestMessage1)