Cannot assign to struct field in a map
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 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.
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.