我想将一片字符串转换为指向字符串
的指针片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)
%!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])
}
答案 0 :(得分:2)
为每次迭代分配for .. range
子句中的迭代值。
spec明确指出:
将迭代值分配给相应的迭代 变量,如赋值语句。
这相当于:
var v string
v = string1
values[0] = &v
v = string2
values[1] = &v
etc...
变量v
仍然存在于相同的内存区域,只是内容发生了变化。因此v
的地址永远不会改变。
答案 1 :(得分:2)
第一个版本不起作用,因为只有一个循环变量v
,在每次迭代中具有相同的地址。循环变量在每次迭代中分配,它会更改其值但不更改其地址,并在每次迭代中追加相同的地址。
您建议的可能解决方案是:附加原始切片的正确切片元素的地址:
for i := range values1 {
values2 = append(values2, &values1[i])
}
这有效,但请注意values2
包含指向values1
的后备数组的地址,因此values1
的后备数组将保留在内存中(不会收集垃圾)直到values1
和values2
变量都无法访问。另请注意,修改values1
的元素会间接影响values2
,因为values2
的元素指向values1
的元素。
另一个解决方案是创建临时局部变量并附加那些地址:
for _, v := range values1 {
v2 := v
values2 = append(values2, &v2)
}
通过这样做,您的values2
切片不会让values1
无法收集垃圾,同时修改values1
中的值也不会反映在values2
中,它们将会独立的。
查看有关循环变量的相关问题:
Why do these two for loop variations give me different behavior?
Golang: Register multiple routes using range for loop slices/map