在golang范围复制之后,所有项目都指向src切片的最后一项

Ric*_*kyA 2 range go

将所有项目从切片(src)复制到新切片(dst)后,dst中的所有项目都指向src的最后一项.

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\n", i, *s)
    }
}

>>> 0 - c
>>> 1 - c
>>> 2 - c
Run Code Online (Sandbox Code Playgroud)

为什么不将"a"和"b"复制到dst切片中?

Ric*_*kyA 7

解决方案很简单,但在对range语句的期望方面具有反直觉性.

变量val只被实例化一次,并保持价值src[i]每一个迭代.它没有实际的指针src[i].而是将值src[i]复制到分配给的内存中val.通过获取指针,val你得到的就是那个,而不是指针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\n", i, *s, s)
    }

    //modify only contents of first index
    *dst[0] = "hi val"

    for i, s := range dst {
        fmt.Printf("%v - %v - %p\n", i, *s, s)
    }
}

>>>>
0 - c - 0x1040a120
1 - c - 0x1040a120
2 - c - 0x1040a120
0 - hi val - 0x1040a120
1 - hi val - 0x1040a120
2 - hi val - 0x1040a120
Run Code Online (Sandbox Code Playgroud)

虽然事后证明这很明显 - for _, val- >:= < - range src- 如果你不知道它,它可以咬你的屁股,所以这个警告.

PS.这也适用于src地图.


One*_*One 5

添加到@RickyA 的答案。

要实现您想要做的事情,您需要执行以下操作:

for i := range src {
    dst[i] = &src[i]
}
Run Code Online (Sandbox Code Playgroud)