Go语言string切片转*string切片遇迭代变量地址重复问题及解决
Go中string切片转*string切片的常见坑
首先来看你写的这段代码:
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)
运行后输出的指针全是同一个地址,这其实是Go语言range循环的一个典型特性导致的——循环变量v是在循环开始前就声明好的单个变量,每次迭代只是把values1里的当前元素值复制给v,而不是每次迭代都创建一个新的v。
所以:
v的内存地址从始至终都是同一个,不管迭代多少次,你取的&v都是这个固定地址- 每次迭代时
v的值会被覆盖成当前元素的内容,最后循环结束时v的值是"c",所以values2里的所有指针都指向这个最终值的地址
你疑惑的"若v不是指针,它的值为何能变化"——其实很简单,v是一个普通的string变量,每次循环只是对它做赋值操作,把当前元素的值复制给它,所以它的值会跟着迭代过程改变,但它自己的内存位置是固定的。
正确的解决方案
你给出的这段代码是完全正确的思路:
values1 := []string{"a", "b", "c"} var values2 []*string for i, _ := range values1 { values2 = append(values2, &values1[i]) }
这里直接取原切片中对应索引元素的地址&values1[i],每个元素在原切片里都有独立的内存位置,所以values2里的每个指针都会指向不同的元素地址,完美解决了问题。
另外还有一种等价写法,在循环内部创建临时变量来保存当前元素,这样每次迭代都会生成新的变量,地址也不同:
values1 := []string{"a", "b", "c"} var values2 []*string for _, v := range values1 { temp := v values2 = append(values2, &temp) }
这种写法也能得到正确的结果,原理是每次循环都创建一个新的temp变量,它的地址是唯一的,保存当前元素的值,再把&temp加入切片。
内容的提问来源于stack exchange,提问作者Martin Magakian
相关产品推荐
相关产品推荐

