
在 go 中,使用 range 遍历切片时,`value` 是每次迭代的副本变量,对其取地址(&value)得到的是同一个栈变量的地址,而非原切片元素的地址;要获取真实元素指针,必须使用 `&slice[index]`。
Go 的 range 循环在遍历切片时,会将每个元素复制到一个复用的局部变量中(即 value),该变量在整个循环生命周期内内存地址不变。因此,&value 始终指向同一块栈内存,导致所有打印出的指针值相同——这并非 bug,而是 Go 语言明确规定的语义。
要真正获取切片中每个结构体元素的地址,必须显式通过索引访问原底层数组:
package main
import "fmt"
type demo struct {
name string
}
func main() {
demoSlice := make([]demo, 3)
demoSlice[0] = demo{"str1"}
demoSlice[1] = demo{"str2"}
demoSlice[2] = demo{"str3"}
pointSlice := make([]*demo, 3)
for index := range demoSlice {
fmt.Printf("{%s}==++++++++++++++%p\n", demoSlice[index], &demoSlice[index])
pointSlice[index] = &demoSlice[index]
}
// 验证指针有效性
for i, p := range pointSlice {
fmt.Printf("pointSlice[%d] -> %+v (address: %p)\n", i, *p, p)
}
}运行结果将显示三个不同且连续的内存地址(如 0x...e0, 0x...e8, 0x...f0),对应切片底层数组中各 demo 实例的真实位置。
⚠️ 注意事项:
- 不要对 range 的 value 取地址并保存(如 &value),它仅在当前迭代有效,且始终是同一地址;
- 若需构建指针切片,优先使用 for i := range slice 或 for i := 0; i
- 对于大结构体,直接取地址可避免不必要的拷贝,提升性能;
- 若切片后续可能发生扩容(如 append),原有元素地址可能失效——此时指针将悬空,需谨慎管理生命周期。
总结:Go 中“获取切片元素指针”的本质,是获取底层数组中对应索引位置的地址。牢记 range value 是副本,而 &slice[i] 才是真相。









