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.
For those looking for a simpler example:
This is wrong:
type myStruct struct{
Field int
}
func main() {
myMap := map[string]myStruct{
"key":{
Field: 1,
},
}
myMap["key"].Field = 5
}
Because myMap["key"]
is not "addressable".
This is correct:
type myStruct struct{
Field int
}
func main(){
myMap := map[string]myStruct{
"key":{
Field: 1,
},
}
// First we get a "copy" of the entry
if entry, ok := myMap["key"]; ok {
// Then we modify the copy
entry.Field = 5
// Then we reassign map entry
myMap["key"] = entry
}
// Now "key".Field is 5
fmt.Println(myMap) // Prints map[key:{5}]
}
Here you have a working example.
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.
For my use case, I needed to update the entries fairly often. Thus, modifying the copy and reassigning it to the map entry would have been very inefficient. An alternative way could be to use a pointer to a struct instead. (I know it won't fit for all use cases, but just in case yours is flexible enough to use either a struct or a pointer to it...)
type bigStruct struct {
val1 int
val2 bool
val3 string
}
newMap := make(map[string]*bigStruct)
newMap["struct1"] = &bigStruct{1, true, "example1"}
// and can now modify the entries normally
newMap["struct1"].val1 = 2
newMap["struct1"].val2 = false
newMap["struct1"].val3 = "example2"
See the full code here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With