0

作为标题,我有代码:

val description= mutableMapOf(
    "father2" to "123",
    "father" to mutableMapOf<String,String>())
description["father"]["child"] = "child value"

如果我试试这个:description["father"]["child"]="child value"

我会得到错误:

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: 
public inline operator fun <K, V> MutableMap<String!, String!>.set(key: String!, value: String!): Unit defined in kotlin.collections
public inline operator fun kotlin.text.StringBuilder /* = java.lang.StringBuilder */.set(index: Int, value: Char): Unit defined in kotlin.text

我能怎么做?

4

4 回答 4

1

这是关于打字(或没有打字)。

description映射由两对创建,一对从 aString到 a String,另一对从 aString到 a MutableMap<String, String>。键都是String,所以 Kotlin 会推断出String键的类型。但是价值观呢?它们是两种完全不相关的类型,除了Any. 所以推断的类型descriptionMutableMap<String, Any>。(您可以在例如 REPL 中进行检查。)

那么,当你提取一个值时,编译器能告诉你什么?几乎没有。它是一个Any,所以你唯一可以确定的是它不为空。

这就是为什么编译器不会将提取的值视为地图的原因。据它所知,它可能不是地图!(我们知道——但这只是因为我们可以看到地图是用什么初始化的,并且从那时起它没有被修改,也没有与任何其他可以修改它的对象或线程共享引用。但这是一种相对罕见的情况。)

Kotlin 是一种强类型语言,这意味着编译器会跟踪所有内容的类型,并努力不让您做任何可能导致运行时错误的事情。你的代码,如果它被编译,ClassCastException任何时候数据与你预期的不完全匹配都会有风险,这几乎不是通往好的程序的途径。

所以,你可以做什么?

最安全的做法是更改您的程序,以便您没有任何带有未知类型值的映射。显然,这取决于你的程序在做什么,所以我们不能在这里提出有用的建议。但是,如果您description是 a MutableMap<String, MutableMap<String, String>>,那么编译器将确切地知道所有内容是什么类型,并且您的预期代码将编译并运行良好。

另一个主要替代方法是在尝试将其视为 map 之前检查该值是什么。一种方法是使用as?安全转换运算符。检查一个值是否属于给定类型;如果是这样,则将其强制转换为该类型;否则,它返回 null。.?然后,仅当值不为空时,您才可以使用安全调用运算符调用方法。把它放在一起:

(description["father"] as? MutableMap<String, String>)?.put("child", "child value")

如果值如您所愿,那将正常工作;如果没有,它将什么都不做并继续。

这是相当冗长的,但它会安全地编译和运行。或者,您可以以更明确的方式执行相同的操作,如下所示:

val child = description["father"]
if (child is MutableMap<String, String>))
    child["child"] = "child value"

(在 中if,编译器知道 的类型child,并使用“智能转换”来允许推杆调用。)

当然,这更啰嗦。但这就是你尝试与类型系统对抗的结果:-)

(哦,顺便说一句,我认为递归数据结构的常用术语是“父”和“子”;我以前从未见过“父”这样使用过。)

于 2020-04-09T18:32:58.363 回答
0

我目前的解决方案:

val description:MutableMap<String,Any> = mutableMapOf(
    "father" to "123"
)

val father2 = mutableMapOf<String,String>()
father2.put("child", "child value")
description["father2"]=father2
于 2020-04-09T18:05:03.717 回答
0

尝试这个:

description["father"]?.put("child", "child value")
于 2020-04-09T16:51:57.760 回答
0

你可以试试这个:

val description = mutableMapOf<String?,MutableMap<String,String>?> 
("father" to mutableMapOf<String,String>())

description.get("father")?.put("Key","Value")
println(description) // {father={Key=Value}}
于 2020-04-09T20:19:15.657 回答