15

Hi I'm new to go and was trying to figure out how maps work. I have made up a little test program and can't seem to get it to work. What I'm doing wrong?

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)
}
1
  • stats.category["aa"] is supposed to be a map of strings to a slice of Events, but you are trying to assign it the value of 66. Commented Jan 24, 2016 at 4:48

3 Answers 3

22

There are couple of issues with the code:

  1. Map needs to be initialized using make function. Currently they are nil

  2. Return value from map is non-addressable, this because if map is growing it needs to relocated which will cause memory address to change. Hence we need to extract value explicitly from map to a variable, update it and assigning it back.

  3. Use pointer

I have updated the solution to show both updated it value returned and assigning it back and pointer.

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)
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your solution it's exactly what I was looking for.
Took me a while to find your post for this answer, but it makes sense now
4

Adding this as a different approach to the problem:

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

Comments

1

There are a few issues with your approach.

  • You aren't initializing you maps. You need to create them first.

  • Maps return copies of their values. So when you pull out "aa" and modify it, you are getting a copy of "aa", changing it, then throwing it away. You need to put it back in the map, or use pointers.

Here's a working example (non-pointer version) on Play.
Notice the construction of the maps, and the re-assignment back to the map when modifying a value.

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.