地图值指针添加到切片的行为

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