嵌套映射的结构体(Golang)

14

你好,我是go语言的新手,正在尝试理解如何使用map。 我编写了一个小测试程序但似乎无法正常运行。 我错在哪里了?

package main

import (
    "fmt"
)

type Stats struct {
    cnt      int
    category map[string]Events
}

type Events struct {
    cnt   int
    event map[string]Event
}

type Event struct {
    value int64
}

func main() {

    stats := new(Stats)
    stats.cnt = 33
    stats.category["aa"].cnt = 66
    stats.category["aa"].event["bb"].value = 99

    fmt.Println(stats.cnt, stats.category["aa"].event["bb"].value)
}

stats.category["aa"] 应该是一个字符串到事件切片的映射,但你试图将其赋值为 66。 - verygoodsoftwarenotvirus
3个回答

22

代码存在几个问题:

  1. 需要使用make函数初始化map。目前它们是nil

  2. 从map返回的值是非可寻址的,因为如果map在增长时需要重新定位,这将导致内存地址发生变化。因此我们需要显式地将值从map中提取到一个变量中,更新它并将其赋回。

  3. 使用指针

我已更新解决方案以显示已更新的值和分配回的值,并使用了指针。

http://play.golang.org/p/lv50AONXyU

package main

import (
    "fmt"
)

type Stats struct {
    cnt      int
    category map[string]Events
}

type Events struct {
    cnt   int
    event map[string]*Event
}

type Event struct {
    value int64
}

func main() {

    stats := new(Stats)
    stats.cnt = 33
    stats.category = make(map[string]Events)
    e, f := stats.category["aa"]
    if !f {
        e = Events{}
    }
    e.cnt = 66

    e.event = make(map[string]*Event)
    stats.category["aa"] = e
    stats.category["aa"].event["bb"] = &Event{}
    stats.category["aa"].event["bb"].value = 99

    fmt.Println(stats)
    fmt.Println(stats.cnt, stats.category["aa"].event["bb"].value)
}

谢谢您的解决方案,这正是我所寻找的。 - Daniel Huckson
找到你的帖子来回答这个问题花了我一些时间,但现在我明白了。 - Atherion

4
作为解决问题的另一种方法,可以尝试添加以下内容:
type Stats struct {
    cnt        int
    categories map[string]*Events
}

func (s *Stats) Category(n string) (e *Events) {
    if s.categories == nil {
        s.categories = map[string]*Events{}
    }
    if e = s.categories[n]; e == nil {
        e = &Events{}
        s.categories[n] = e
    }
    return
}

type Events struct {
    cnt    int
    events map[string]*Event
}

func (e *Events) Event(n string) (ev *Event) {
    if e.events == nil {
        e.events = map[string]*Event{}
    }
    if ev = e.events[n]; ev == nil {
        ev = &Event{}
        e.events[n] = ev
    }
    return
}

type Event struct {
    value int64
}

func main() {
    var stats Stats
    stats.cnt = 33
    stats.Category("aa").cnt = 66
    stats.Category("aa").Event("bb").value = 99

    fmt.Println(stats)
    fmt.Println(stats.cnt, stats.Category("aa").Event("bb").value)
}

playground


1
你的方法存在一些问题。
  • 你没有初始化地图。你需要先创建它们。

  • 地图返回值的副本。因此,当你取出"aa"并修改它时,你得到的是"aa"的一个副本,改变它,然后将其丢弃。你需要把它放回地图中,或者使用指针。

这里有一个在Play上工作的示例(非指针版本)。请注意地图的构建以及在修改值时重新分配到地图中。

package main

import (
    "fmt"
)

type Stats struct {
    cnt      int
    category map[string]Events
}

type Events struct {
    cnt   int
    event map[string]Event
}

type Event struct {
    value int64
}

func main() {
    stats := &Stats{category: map[string]Events{}}
    stats.cnt = 33
    tmpCat, ok := stats.category["aa"]
    if !ok {
        tmpCat = Events{event: map[string]Event{}}
    }
    tmpCat.cnt = 66
    tmpEv := tmpCat.event["bb"]

    tmpEv.value = 99
    tmpCat.event["bb"] = tmpEv
    stats.category["aa"] = tmpCat

    fmt.Println(stats.cnt, stats.category["aa"].event["bb"].value)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接