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 中的嵌套地图有问题吗? 或者嵌套地图没有多括号支持?

90936 次浏览

用于映射类型的 零价值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)

输出(在 去游乐场上尝试) :

map[a:map[w:x] b:map[w:x] c:map[w:x]]

请注意,当您声明一个 map 类型的变量并使用 复合文字对其进行初始化(如在 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)

输出是相同的。请在 去游乐场上尝试。

除了 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)

输出是相同的。用 去游乐场试试。添加键“ d”以演示使用空映射的映射。

虽然对这个问题最直接的回答是像前面描述的那样初始化嵌套映射,但是还有另一种可能的选择,这取决于您的访问模式。如果您需要一个真正层次化的地图系统,那么以前的答案就可以了。但是,如果您只是需要使用多个方面在地图中查找值,请继续阅读!

映射使用 结构作为键是完全可以接受的(事实上,任何 差不多都可以使用)。因此,你可以使用一个带有结构键的单一地图,比如 这个例子来自 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"}]

我不经常看到这样的地图,相反,很多人首先使用嵌套的变体,我认为这可能并不总是正确的适合。

下面的解决方案可能对您有用。

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,
}