Golang 中的嵌套映射
Nested maps in Golang
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 中的嵌套映射有问题吗?还是嵌套地图不支持多括号?
地图类型的 zero value 是 nil
。它尚未初始化。您不能将值存储在 nil
映射中,这是运行时恐慌。
在上一个示例中,您初始化了(外部)data
映射,但它没有任何条目。当您像 data["a"]
一样对其进行索引时,由于其中还没有带有 "a"
键的条目,因此将其索引为 returns 值类型的零值,对于地图来说是 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]]
请注意,当您声明一个地图类型的变量并使用 composite literal 对其进行初始化时(如 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 Playground.
上试试
除了icza的回答。地图初始化可以写成short form:
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 Playground 上试试吧。添加键 "d" 以演示空映射的映射。
虽然这个问题最直接的答案是如前所述初始化嵌套映射,但根据您的访问模式,还有另一个可能的选择。如果您需要一个真正的地图分层系统,那么前面的答案就可以了。但是,如果您只需要使用多个方面在地图中查找值,请继续阅读!
地图使用结构作为键是完全可以接受的(事实上,任何comparable can be used). Thus, you can use a single map with struct keys like this example from the Golang blog,这是一个按国家/地区跟踪页面点击的点击计数器:
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"}]
我不太经常看到这样的地图,相反,许多人首先使用嵌套变体,我认为这可能并不总是合适的。
以下解决方案可能对您有用。
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,
}
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 中的嵌套映射有问题吗?还是嵌套地图不支持多括号?
地图类型的 zero value 是 nil
。它尚未初始化。您不能将值存储在 nil
映射中,这是运行时恐慌。
在上一个示例中,您初始化了(外部)data
映射,但它没有任何条目。当您像 data["a"]
一样对其进行索引时,由于其中还没有带有 "a"
键的条目,因此将其索引为 returns 值类型的零值,对于地图来说是 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]]
请注意,当您声明一个地图类型的变量并使用 composite literal 对其进行初始化时(如 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 Playground.
上试试除了icza的回答。地图初始化可以写成short form:
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 Playground 上试试吧。添加键 "d" 以演示空映射的映射。
虽然这个问题最直接的答案是如前所述初始化嵌套映射,但根据您的访问模式,还有另一个可能的选择。如果您需要一个真正的地图分层系统,那么前面的答案就可以了。但是,如果您只需要使用多个方面在地图中查找值,请继续阅读!
地图使用结构作为键是完全可以接受的(事实上,任何comparable can be used). Thus, you can use a single map with struct keys like this example from the Golang blog,这是一个按国家/地区跟踪页面点击的点击计数器:
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"}]
我不太经常看到这样的地图,相反,许多人首先使用嵌套变体,我认为这可能并不总是合适的。
以下解决方案可能对您有用。
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,
}