Как установить значение для дочерней карты в карте отца в kotlin? - PullRequest
0 голосов
/ 09 апреля 2020

в качестве заголовка, у меня есть код:

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 ]

1 голос
/ 09 апреля 2020

Речь идет о наборе текста (или его отсутствии).

Карта description создается из двух пар: одна от String до String, а другая от String до MutableMap<String, String>. Обе клавиши String, поэтому Kotlin выведет String для типа ключа. Но как насчет ценностей? Это два совершенно не связанных типа, без общего суперкласса, кроме Any. Таким образом, тип description определяется как MutableMap<String, Any>. (Вы можете проверить это, например, в REPL.)

Итак, когда вы извлекаете значение, что может сказать об этом компилятор? Почти ничего. Это Any, поэтому единственное, в чем вы можете быть уверены, это то, что он не равен нулю.

Вот почему компилятор не рассматривает это извлеченное значение как карту; насколько он знает, это не может быть быть картой ! ( Мы знаем - но только потому, что мы можем видеть, с чем была инициализирована карта, и что она не изменялась с тех пор, и ссылка не передается другим объектам или потокам, которые могут ее изменить. Но это относительно редкое обстоятельство.)

Kotlin - язык со строгой типизацией, что означает, что компилятор отслеживает тип всего и очень старается не позволить вам сделать что-либо, что может вызвать ошибку во время выполнения. Ваш код, если он скомпилирован, рискует ClassCastException в любое время, когда данные не совсем соответствуют ожидаемым, что вряд ли является путём к хорошим программам.

Итак, что вы можете сделать?

Самым безопасным было бы изменить вашу программу, чтобы у вас не было 1035 * карт с неизвестными типами значений . Очевидно, это зависит от того, что делает ваша программа, поэтому мы не можем сделать полезные предложения здесь. Но если бы ваш description был MutableMap<String, MutableMap<String, String>>, то компилятор точно знал бы, к какому типу относится все, и ваш намеченный код скомпилировался бы и нормально работал.

Другой основной альтернативой будет проверьте каково значение, прежде чем пытаться рассматривать его как карту . Один из способов сделать это - использовать оператор безопасного приведения as?. Это проверяет, имеет ли значение данный тип; если так, это приведено к этому типу; в противном случае возвращается ноль. Затем вы можете использовать оператор безопасного вызова .? для вызова метода, только если значение не равно нулю. Сложив это вместе:

(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 и использует «умное приведение» для позвольте клюшке.)

Это, конечно, еще более скучно. Но вот что вы получаете, пытаясь работать с системой типов: -)

(О, и, кстати, я думаю, что обычная терминология для рекурсивных структур данных - это «родитель» и «ребенок»; I » мы не видели, чтобы «отец» использовал это раньше.)

0 голосов
/ 09 апреля 2020

Вы можете попробовать это:

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

description.get("father")?.put("Key","Value")
println(description) // {father={Key=Value}}
0 голосов
/ 09 апреля 2020

Мое текущее решение:

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

val father2 = mutableMapOf<String,String>()
father2.put("child", "child value")
description["father2"]=father2
0 голосов
/ 09 апреля 2020

Попробуйте это:

description["father"]?.put("child", "child value")
...