45
votes

I have the data structure like this:

type Snapshot struct {
  Key   string
  Users []Users
}

snapshots := make(map[string] Snapshot, 1)

// then did the initialization
snapshots["test"] = Snapshot {
  Key: "testVal",
  Users: make([]Users, 0),
}

Users is another struct.

Then when I tried to append some new Users values in the Users slice like this:

snapshots["test"].Users = append(snapshots["test"].Users, user)

I kept getting this error:

cannot assign to struct field snapshots["test"].Users in map

Also tried the workaround here https://github.com/golang/go/issues/3117 so like this:

tmp := snapshots["test"].Users
tmp = append(tmp, user)
snapshots["test"].Users = tmp

But no luck, still exactly same error.

And also tried to declare the map with pointer, so: snapshots := make(map[string] *Snapshot, 1), still no luck.

2
@keno, thanks for ur response, finally I figured out the reason why after I already use pointer it still cannot work, it is because I did snapshots := make(map[string] Snapshot, 1), then i think the len(snapshots) will be 1, later I initialized the map with one for loop, which used the value len(snapshots),.... so that mean the initialization process never get run.... then after i used pointer, i get this error: panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x78 pc=0x427bb9d]lnshi

2 Answers

12
votes

First, for this question, the solution in this post Why do I get a "cannot assign" error when setting value to a struct as a value in a map? works perfectly fine.

Then, finally figured out why after I already changed to use pointer my case still doesn't work, refer to the below very simple code:

a := make([]int, 3)
fmt.Println(len(a))

b := make(map[string]string, 3)
fmt.Println(len(b))

What do think the output will be? I simply thought it is all would be: 3, but actually for the map, the output will be 0

Then later in the map initialization process, i used a for loop and with this value len(snapshots), that means the initialization process will never get run...

Yea, that is the reason.

1
votes

What I ended up doing to use my struct map in a loop was the following:

type testStruct struct {
  a string
  b int
}

func main() {
  mapTest := make(map[string]testStruct)
  abc := [3]string{"a", "b", "c"}

  for i := 0; i < len(abc); i++ {
    var temp testStruct
    temp.a = abc[i]
    temp.b = i
    mapTest[abc[i]] = temp
  }

  fmt.Println(mapTest)
}

Output should be:

map[b:{b 1} c:{c 2} a:{a 0}]

It's not appending, but should work to assign multiple values to a struct map, alternatively you could do the following and allow the map to reference its own values:

func main() {
  mapTest := make(map[string]testStruct)

  abc := [3]string{"a", "b", "c"}
  for i := 0; i < len(abc)*2; i++ {
    temp := mapTest[abc[i%3]]
    temp.a = abc[i%3]
    temp.b = temp.b + i
    mapTest[abc[i%3]] = temp
  }

  fmt.Println(mapTest)
}

Which should output:

map[a:{a 3} b:{b 5} c:{c 7}]

Note that no errors are raised when we reference an empty struct value, this is because when we initialize our struct, its values start out as empty values but not nil (0 for int, "" for string, etc.)