Go中切片指针解引用未关联原切片值问题排查
问题根源:循环变量的复用与值拷贝
你的问题出在range循环的变量处理上:
在这段循环代码里:
for _, x := range x { g = append(g, &x) }
这里的x是循环迭代时创建的临时变量,每次循环都会把原切片x的元素值拷贝到这个临时变量里,而且这个临时变量在整个循环过程中是复用同一块内存地址的。你把&x添加到指针切片g中,相当于所有指针都指向了同一个临时变量的地址,而非原切片x中各个元素的实际地址。
这就导致:
- 修改
*g[0]时,只是修改了那个临时变量的值(后续循环的临时变量已经被覆盖,所以你看到的*g里只有第一个值变了,本质是最后一次循环后临时变量被改成了10); - 修改原切片
x[1]时,指针切片g里的指针根本没指向原切片元素,自然看不到变化。
修正方案:通过索引获取原元素地址
改成用索引遍历原切片,直接取原切片元素的地址,这样指针切片里的每个指针都会指向原切片对应元素的真实内存地址:
package main import "fmt" func main() { var x []int = []int{5,4,3,2,1} var y *[]int = &x var g []*int // 改用索引遍历,取原切片元素的地址 for i := range x { g = append(g, &x[i]) } fmt.Println("x, y, g, *g =") fmt.Println(x) fmt.Println(y) fmt.Println(g) printPtr(g) fmt.Println() fmt.Println() fmt.Println("Setting *g[0] to 10") *g[0] = 10 fmt.Println("*g =") printPtr(g) fmt.Println("x =", x) fmt.Println() fmt.Println() fmt.Println("Setting x[1] to 17") x[1] = 17 fmt.Println("x, y, *g =") fmt.Println(x) fmt.Println(y) printPtr(g) fmt.Println() } func printPtr(i []*int) { for _, v := range i { fmt.Print(*v) fmt.Print(" ") } }
修正后的输出:
x, y, g, *g = [5 4 3 2 1] &[5 4 3 2 1] [0x140000a6010 0x140000a6018 0x140000a6020 0x140000a6028 0x140000a6030] 5 4 3 2 1 Setting *g[0] to 10 *g = 10 4 3 2 1 x = [10 4 3 2 1] Setting x[1] to 17 x, y, *g = [10 17 3 2 1] &[10 17 3 2 1] 10 17 3 2 1
可以看到现在两种修改操作都能同步生效了,完全符合你的需求。
内容的提问来源于stack exchange,提问作者kanennn
相关产品推荐
相关产品推荐

