func TestMapValuePointer2(t *testing.T) {
fmt.Println("Test Map Value Pointer 2")
m := map[string]int{"rsc": 3711, "r": 2138, "gri": 1908, "adg": 912}
n := len(m)
array := make([]*int, n)
i := 0
for _, v := range m {
array[i] = &v
fmt.Printf("Add to array: %d
", v)
i++
}
for _, k := range array {
fmt.Printf("Value: %d
", *k)
}
}
The output is not:
Value: 912 Value: 3711 Value: 2138 Value: 1908
Instead, the output maybe like:
Value: 912 Value: 912 Value: 912 Value: 912
Can someone explain why the results are like the above?
Quoting from this doc:
[...] each iteration of the loop uses the same instance of the variable v, so each closure shares that single variable [...]
In other words, the loop variable v
is reused in all iterations, so your assigning the same pointer to all your slice elements.
Variables declared inside the loop won't be recycled like that, so this will work as you would expect:
for _, v := range m {
vv := v
array[i] = &vv
fmt.Printf("Add to array: %d
", v)
i++
}
Btw, you haven't explained why you want to use *int
as the type of the values. All this would be simpler if you used simply int
values.
The issue here is that the variable v
created during the loop is actually a copy of the value we have in the map. The memory related to v
is allocated once at the start of the loop and is re-used later on for other values, as the last value here points to is 912 in this case you're seeing 912 inside the array.
A simple proof for this will be: https://play.golang.org/p/K0yAbEIf3G
One fix for this will be to change your map value to be *int pointers instead of values and later on we can dereference them to get the actual values:
package main
import "fmt"
func main() {
fmt.Println("Test Map Value Pointer 2")
a, b, c, d := 3711, 2138, 1908, 912
m := map[string]*int{"rsc": &a, "r": &b, "gri": &c, "adg": &d}
n := len(m)
array := make([]*int, n)
i := 0
for _, v := range m {
array[i] = v
fmt.Printf("Add to array: %d
", *v)
i++
}
for _, k := range array {
fmt.Printf("Value: %d
", *k)
}
}
Playground link: https://play.golang.org/p/TpkXlCElLx