The solution is simple, but counter intuitive in terms of what you would expect of the range
statement.
The variable val
is instantiated only once and holds the value of src[i]
in every iteration. It does not has the actual pointer to src[i]
. Instead the value of src[i]
is copied to the memory that is assigned to val
. By taking the pointer of val
you get exactly that, and not the pointer to src[i]
.
package main
import (
"fmt"
)
func main() {
src := []string{"a", "b", "c"}
dst := []*string{}
for _, val := range src {
dst = append(dst, &val)
}
for i, s := range dst {
fmt.Printf("%v - %v - %p
", i, *s, s)
}
//modify only contents of first index
*dst[0] = "hi val"
for i, s := range dst {
fmt.Printf("%v - %v - %p
", i, *s, s)
}
}
>>>>
0 - c - 0x1040a120
1 - c - 0x1040a120
2 - c - 0x1040a120
0 - hi val - 0x1040a120
1 - hi val - 0x1040a120
2 - hi val - 0x1040a120
While in hindsight this is obvious - for _, val
-> := <- range src
- it can can bite you in the ass if you are unaware of it, so therefore this warning.
PS. this also applies to src
as a map.