将字符串切片转换为指向字符串的指针切片

Mar*_*ian 3 memory string pointers for-loop go

我想将一段字符串转换为一段指向字符串的指针

values1 := []string{"a", "b", "c"}
var values2 []*string
for _, v := range values1 {
    fmt.Printf("%p | %T\n", v, v)
    values2 = append(values2, &v)
}
fmt.Println(values2)
Run Code Online (Sandbox Code Playgroud)

%!p(string=a) => 字符串
%!p(string=b) => 字符串
%!p(string=c) => 字符串
[0xc42000e1d0 0xc42000e1d0 0xc42000e1d0]

根据我的理解,
我的变量v似乎是一个字符串,而不是一个指向字符串的指针。
因此v应该values1在迭代时复制。

显然我是不正确的,因为v仍然有相同的地址0xc42000e1d0。如果不是指针,值
如何v改变?

如需快速解决方案,请使用:

values1 := []string{"a", "b", "c"}
var values2 []*string
for i, _ := range values1 {
    values2 = append(values2, &values1[i])
}
Run Code Online (Sandbox Code Playgroud)

icz*_*cza 5

第一个版本不起作用,因为只有一个循环变量v,它在每次迭代中都有相同的地址。循环变量在每次迭代中被赋值,它改变了它的值而不是它的地址,并且你在每次迭代中附加这个相同的地址。

一个可能的解决方案是您提出的:附加原始切片的正确切片元素的地址:

for i := range values1 {
    values2 = append(values2, &values1[i])
}
Run Code Online (Sandbox Code Playgroud)

这是可行的,但请注意,它values2包含指向 的后备数组的地址values1,因此后备数组values1将保存在内存中(不会被垃圾收集),直到values1values2变量都无法访问为止。另请注意,修改 的元素values1将产生values2间接影响,因为 的元素values2指向 的元素values1

另一种解决方案是创建临时局部变量并附加这些变量的地址:

for _, v := range values1 {
    v2 := v
    values2 = append(values2, &v2)
}
Run Code Online (Sandbox Code Playgroud)

通过这样做,您的values2切片将不会阻止values1垃圾收集,并且修改中的值values1也不会反映在 中values2,它们将是独立的。

查看循环变量的相关问题:

为什么这两个 for 循环变体会给我不同的行为?

Golang:使用循环切片/地图的范围注册多个路由