如何在kotlin中为父映射中的child映射设置值?
How to set value to the child map in the father map in kotlin?
如标题,我有代码:
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
我该怎么办?
试试这个:
description["father"]?.put("child", "child value")
我目前的解决方案:
val description:MutableMap<String,Any> = mutableMapOf(
"father" to "123"
)
val father2 = mutableMapOf<String,String>()
father2.put("child", "child value")
description["father2"]=father2
这是关于打字(或不打字)的问题。
description
地图由两对创建,一对从 String
到 String
,另一对从 String
到 MutableMap<String, String>
.这两个键都是 String
,所以 Kotlin 会推断出 String
键的类型。但是价值观呢?它们是两个完全不相关的类型,除了 Any
之外没有共同的超类。所以description
的类型被推断为MutableMap<String, Any>
。 (您可以在 REPL 中查看。)
那么,当你提取一个值时,编译器能告诉它什么?几乎没有。这是一个 Any
,因此您唯一可以确定的是它不为空。
这就是为什么 编译器没有像对待映射那样处理提取的值;据它所知,它可能 不是 地图 ! (我们 知道——但只是因为我们可以看到映射是用什么初始化的,并且从那时起它就没有被修改过,引用也没有与任何其他可以修改它的对象或线程共享. 但这是一种相对罕见的情况。)
Kotlin 是一种强类型语言,这意味着编译器会跟踪所有内容的类型,并且非常努力地不让您做任何可能导致 运行time 错误的事情。如果您的代码经过编译,则只要数据与您的预期不完全匹配,就会冒 ClassCastException
的风险,这很难成为好的程序。
那么,你能做什么?
最安全的做法是更改您的程序,这样您就不会拥有任何具有未知类型值的地图。显然,这取决于你的程序在做什么,所以我们不能在这里提出有用的建议。但是,如果您的 description
是 MutableMap<String, MutableMap<String, String>>
,那么编译器会确切地知道所有内容是什么类型,并且您的预期代码会编译并且 运行 没问题。
另一个主要的替代方法是检查值是什么,然后再尝试将其视为地图。一种方法是使用 as?
安全转换运算符。检查一个值是否属于给定类型;如果是这样,则将其转换为该类型;否则,它 returns 为空。然后,您可以使用 .?
安全调用运算符仅在值不为空时调用方法。放在一起:
(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
的类型,并使用“智能转换”来允许 putter 调用。)
当然,这就更啰嗦了。但这就是您尝试针对类型系统工作所得到的结果:-)
(哦,顺便说一下,我认为递归数据结构的常用术语是“父”和“子”;我以前从未见过这样使用“父亲”。)
你可以试试这个:
val description = mutableMapOf<String?,MutableMap<String,String>?>
("father" to mutableMapOf<String,String>())
description.get("father")?.put("Key","Value")
println(description) // {father={Key=Value}}
如标题,我有代码:
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
我该怎么办?
试试这个:
description["father"]?.put("child", "child value")
我目前的解决方案:
val description:MutableMap<String,Any> = mutableMapOf(
"father" to "123"
)
val father2 = mutableMapOf<String,String>()
father2.put("child", "child value")
description["father2"]=father2
这是关于打字(或不打字)的问题。
description
地图由两对创建,一对从 String
到 String
,另一对从 String
到 MutableMap<String, String>
.这两个键都是 String
,所以 Kotlin 会推断出 String
键的类型。但是价值观呢?它们是两个完全不相关的类型,除了 Any
之外没有共同的超类。所以description
的类型被推断为MutableMap<String, Any>
。 (您可以在 REPL 中查看。)
那么,当你提取一个值时,编译器能告诉它什么?几乎没有。这是一个 Any
,因此您唯一可以确定的是它不为空。
这就是为什么 编译器没有像对待映射那样处理提取的值;据它所知,它可能 不是 地图 ! (我们 知道——但只是因为我们可以看到映射是用什么初始化的,并且从那时起它就没有被修改过,引用也没有与任何其他可以修改它的对象或线程共享. 但这是一种相对罕见的情况。)
Kotlin 是一种强类型语言,这意味着编译器会跟踪所有内容的类型,并且非常努力地不让您做任何可能导致 运行time 错误的事情。如果您的代码经过编译,则只要数据与您的预期不完全匹配,就会冒 ClassCastException
的风险,这很难成为好的程序。
那么,你能做什么?
最安全的做法是更改您的程序,这样您就不会拥有任何具有未知类型值的地图。显然,这取决于你的程序在做什么,所以我们不能在这里提出有用的建议。但是,如果您的 description
是 MutableMap<String, MutableMap<String, String>>
,那么编译器会确切地知道所有内容是什么类型,并且您的预期代码会编译并且 运行 没问题。
另一个主要的替代方法是检查值是什么,然后再尝试将其视为地图。一种方法是使用 as?
安全转换运算符。检查一个值是否属于给定类型;如果是这样,则将其转换为该类型;否则,它 returns 为空。然后,您可以使用 .?
安全调用运算符仅在值不为空时调用方法。放在一起:
(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
的类型,并使用“智能转换”来允许 putter 调用。)
当然,这就更啰嗦了。但这就是您尝试针对类型系统工作所得到的结果:-)
(哦,顺便说一下,我认为递归数据结构的常用术语是“父”和“子”;我以前从未见过这样使用“父亲”。)
你可以试试这个:
val description = mutableMapOf<String?,MutableMap<String,String>?>
("father" to mutableMapOf<String,String>())
description.get("father")?.put("Key","Value")
println(description) // {father={Key=Value}}