为什么golang行为中的字符串指针在范围循环中违反直觉?

With this code: https://play.golang.org/p/tCm1W-K-6ob

This code would print: [c c c], but [a b c] is excepted.

type A struct {
    a *string
}

func f() {
    slist := []string{"a", "b", "c"}
    list := make([]*A, len(slist))
    for i, v := range slist {
        item := &A{
            a: &v,
        }
        list[i] = item
    }
    fmt.Printf("[%s %s %s]", *list[0].a, *list[1].a, *list[2].a)
}

func main() {
    f()
}

Why the list is not ["a", "b", "c"]? What happened to the range or the &string?

https://play.golang.org/p/utJrUmxeqfh

package main

import (
    "fmt"
)

func main() {
    foo := []int{1, 2, 3}
    for _, f := range foo {
        fmt.Printf("value is %d, addr is %p 
", f, &f)
    }
    fmt.Println("Hello, playground")
}
value is 1, addr is 0x414020 
value is 2, addr is 0x414020 
value is 3, addr is 0x414020 
Hello, playground

the value f in range has the same address

The items all contain the address of the one local variable v.

If your goal is to assign the address of the slice element the a field, then do the following:

for i := range slist {
    item := &A{
        a: &slist[i],  // address of element instead of local variable.
    }
    list[i] = item
}

Run it on the Go Playground.

You can also get the output you want by creating a new variable on each loop iteration:

for i, v := range slist {
    v := v  // create new value on each iteration.
    item := &A{
        a: &v,
    }
    list[i] = item
}

Run it on the Go Playground.

You can try this

Here I can run your code and do some changes.

https://play.golang.org/p/GmU3goeOKdF

here is code

package main

import (
    "fmt"
)

type A struct {
    a  *string
}

func f() {
    slist := []string{"a", "b", "c"}
    list := make([]*A, len(slist))
    for i, v := range slist {
        item := &A{
            a: &v,
        }
        list[i] = item

    fmt.Printf("%s", *list[i].a)
    }
}
func main() {
    f()
}

Output abc

The thing is that the iterator variable is allocated only once and the value it points to is changed with each iteration of the loop:

package main

import (
    "fmt"
)

type A struct {
    a *string
}

func f() {
    slist := []string{"a", "b", "c"}
    list := make([]*A, len(slist))

    // v is only allocated once and the value at it's address is changed
    // on each iteration.
    for i, v := range slist {
        fmt.Printf("Iteration %d: address of v %#v, value of v \"%s\"
", i+1, &v, v)
        // Add in a temp variable, which will get allocated
        // and hence have a new address each iteration.
        t := v

        // Now assign that temp variable's address to the Item's a.
        list[i] = &A{
            a: &t,
        }
    }
    fmt.Printf("[%s %s %s]", *list[0].a, *list[1].a, *list[2].a)
}

func main() {
    f()
}

Run on playground

However, I have a strong feeling that this is unintuitive because we are pretty much talking of premature optimization. (A bit simplified): A string in Go is basically a slice of bytes([]byte), with a slice already being a pointer to the backing array. See Go Slices: usage and internals for details.