Вложенные карты в Голанге
func main() {
var data = map[string]string{}
data["a"] = "x"
data["b"] = "x"
data["c"] = "x"
fmt.Println(data)
}
Это работает.
func main() {
var data = map[string][]string{}
data["a"] = append(data["a"], "x")
data["b"] = append(data["b"], "x")
data["c"] = append(data["c"], "x")
fmt.Println(data)
}
Это также работает.
func main() {
var w = map[string]string{}
var data = map[string]map[string]string{}
w["w"] = "x"
data["a"] = w
data["b"] = w
data["c"] = w
fmt.Println(data)
}
Это бежит снова!
func main() {
var data = map[string]map[string]string{}
data["a"]["w"] = "x"
data["b"]["w"] = "x"
data["c"]["w"] = "x"
fmt.Println(data)
}
Но это не удалось!?
Есть ли проблема с вложенными картами в Go? Или нет поддержки нескольких скобок для вложенных карт?
4 ответа
Нулевое значение для типов карт nil
, Это еще не инициализировано. Вы не можете хранить значения в nil
карта, это паника во время выполнения.
В вашем последнем примере вы инициализируете (внешний) data
карта, но она не имеет записей. Когда вы индексируете это как data["a"]
, поскольку нет записи с "a"
введите его, индексирование возвращает нулевое значение типа значения, которое nil
для карт. Таким образом, пытаясь назначить data["a"]["w"]
это паника во время выполнения.
Вы должны инициализировать карту перед сохранением в ней элементов, например:
var data = map[string]map[string]string{}
data["a"] = map[string]string{}
data["b"] = make(map[string]string)
data["c"] = make(map[string]string)
data["a"]["w"] = "x"
data["b"]["w"] = "x"
data["c"]["w"] = "x"
fmt.Println(data)
Вывод (попробуйте на Go Playground):
map[a:map[w:x] b:map[w:x] c:map[w:x]]
Обратите внимание, что когда вы объявляете переменную типа карты и инициализируете ее составным литералом (как в var data = map[string]string{}
), что также считается инициализацией.
Обратите внимание, что вы также можете инициализировать свои вложенные карты с помощью составного литерала:
var data = map[string]map[string]string{
"a": map[string]string{},
"b": map[string]string{},
"c": map[string]string{},
}
data["a"]["w"] = "x"
data["b"]["w"] = "x"
data["c"]["w"] = "x"
fmt.Println(data)
Выход такой же. Попробуйте это на игровой площадке Go.
Хотя наиболее простой ответ на этот вопрос - инициализировать вложенные карты, как описано ранее, существует еще один потенциальный вариант, зависящий от вашего шаблона доступа. Если вам нужна действительно иерархическая система карт, тогда подойдут предыдущие ответы. Однако, если вам просто нужно искать значения на карте, используя несколько аспектов, читайте дальше!
Для карт вполне допустимо использовать структуры в качестве ключей (фактически, можно использовать все, что сопоставимо). Таким образом, вы можете использовать одну карту со структурными ключами, как в этом примере из блога Golang, который представляет собой счетчик посещений, который отслеживает посещения страниц по странам:
type Key struct {
Path, Country string
}
hits := make(map[Key]int)
// set: Vietnamese person visiting the home page
hits[Key{"/", "vn"}]++
// get: see how many Chinese persons read the spec
n := hits[Key{"/ref/spec", "cn"}]
Я не вижу подобные карты достаточно часто, вместо этого многие люди сначала тянутся к вложенному варианту, который, я думаю, может не всегда подходить.
В дополнение к ответу icza. Инициализация карты может быть записана в краткой форме:
var data = map[string]map[string]string{
"a": map[string]string{
"w": "x"},
"b": map[string]string{
"w": "x"},
"c": map[string]string{
"w": "x"},
"d": map[string]string{},
}
fmt.Println(data)
Выход такой же. Попробуйте это на игровой площадке Go. Ключ "d" добавлен для демонстрации сопоставления с пустой картой.
Приведенное ниже решение может быть вам полезно.
var data = map[string]interface{}{
"publishInfo": map[string]interface{}{
"title": publishInfo.Title,
"description": publishInfo.Desc,
"thumbnail": publishInfo.ImageSrc,
"url": publishInfo.URL,
"tags": publishInfo.Tags,
},
"revision": draftInfo.Revision,
}