Golang中的嵌套地图

Özg*_*çın 39 dictionary go square-bracket

func main() {
    var data = map[string]string{}
    data["a"] = "x"
    data["b"] = "x"
    data["c"] = "x"
    fmt.Println(data)
}
Run Code Online (Sandbox Code Playgroud)

它运行.

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)
}
Run Code Online (Sandbox Code Playgroud)

它也运行.

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)
}
Run Code Online (Sandbox Code Playgroud)

它再次运行!

func main() {
    var data = map[string]map[string]string{}
    data["a"]["w"] = "x"
    data["b"]["w"] = "x"
    data["c"]["w"] = "x"
    fmt.Println(data)
}
Run Code Online (Sandbox Code Playgroud)

但它失败了!?

Go中的嵌套地图有问题吗?或者嵌套地图没有多个括号支持?

icz*_*cza 52

地图类型的零值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)
Run Code Online (Sandbox Code Playgroud)

输出(在Go Playground上试试):

map[a:map[w:x] b:map[w:x] c:map[w:x]]
Run Code Online (Sandbox Code Playgroud)

请注意,当您声明一个地图类型的变量并使用复合文字(如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)
Run Code Online (Sandbox Code Playgroud)

输出是一样的.在Go Playground尝试一下.

  • 在迭代地填充映射的情况下,可以在赋值之前检查nil值:`if data ["c"] == nil {data ["c"] = map [string] string {}}`这有助于避免从地图中丢失数据. (5认同)

Dom*_*nes 16

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

映射使用结构体作为键是完全可以接受的(实际上,任何可以比较的东西都可以使用)。因此,您可以使用带有结构键的单个映射,就像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"}]
Run Code Online (Sandbox Code Playgroud)

我很少看到这样的地图,而是很多人首先使用嵌套变体,我认为这可能并不总是合适的。


Vla*_*lin 13

除了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)
Run Code Online (Sandbox Code Playgroud)

输出是一样的。在Go Playground上试一试。添加了键“d”以演示带有空映射的映射。