Reputation: 15492
I have an array of pointers to structs. The structs have a name
field. I want to create a map from names to pointers to structs.
Why are all of the values in the registry
map identical?
package main
import "fmt"
type Thing struct {
Name string
Value int
}
type Registry map[string]*Thing
func toRegistry(things *[]Thing) Registry {
registry := make(Registry)
for _, thing := range *things {
registry[thing.Name] = &thing
}
return registry
}
func main() {
things := []Thing{{"thingA", 1}, {"thingB", 2}}
registry := toRegistry(&things)
fmt.Println(registry)
}
Sample output: map[thingB:0x10436180 thingA:0x10436180]
Per @tvblah's suggestion, things
was already a slice, so there's no need to point to it:
package main
import "fmt"
type Thing struct {
Name string
Value int
}
type Registry map[string]*Thing
func toRegistry(things []Thing) Registry {
registry := make(Registry)
for _, thing := range things {
registry[thing.Name] = &thing
}
return registry
}
func main() {
things := []Thing{{"thingA", 1}, {"thingB", 2}}
registry := toRegistry(things)
fmt.Println(registry)
Upvotes: 1
Views: 1101
Reputation: 637
You may reassign thing
to another local variable on each iteration and store new variable in registry.
package main
import "fmt"
type Thing struct {
Name string
Value int
}
type Registry map[string]*Thing
func toRegistry(things *[]Thing) Registry {
registry := make(Registry)
for _, thing := range *things {
t := thing
registry[thing.Name] = &t
}
return registry
}
func main() {
things := []Thing{{"thingA", 1}, {"thingB", 2}}
registry := toRegistry(&things)
fmt.Println(registry)
}
Upvotes: 2
Reputation: 206
Each map value is a pointer to the single local variable thing
.
One fix is to add an pointer to the slice element:
func toRegistry(things []Thing) Registry {
registry := make(Registry)
for i := range things {
registry[things[i].Name] = &things[i]
}
return registry
}
Another option is to store pointers to Thing
in the slice:
func toRegistry(things []*Thing) Registry {
registry := make(Registry)
for _, thing := range things {
registry[thing.Name] = thing
}
return registry
}
func main() {
things := []*Thing{&Thing{"thingA", 1}, &Thing{"thingB", 2}}
registry := toRegistry(things)
fmt.Println(registry)
}
I changed the function argument from a pointer to a slice to a slice. This change has no impact on the issue raised on the question, but it's generally how Go code is written. Pointers to slices are rarely used in Go.
Upvotes: 3