贝利信息

如何在 Go 中正确从切片获取结构体指针

日期:2026-01-21 00:00 / 作者:花韻仙語

在 go 中,使用 range 遍历切片时,value 是副本而非原元素引用;直接取 &value 会得到同一个局部变量地址,导致所有指针指向同一内存位置。正确方式是通过索引取址:&slice[i]。

Go 的 range 循环在遍历切片时,会将每个元素复制到循环变量 value 中(而非传递引用),因此 &value 始终是该局部变量在栈上的固定地址——无论迭代多少次,这个地址都不变。这正是你观察到所有指针值相同的根本原因。

要获取切片中各结构体元素的真实地址,必须绕过 value 副本,直接对底层数组元素取址。以下是修正后的完整示例:

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 i := range demoSlice {
        fmt.Printf("{%s}==++++++++++++++%p\n", demoSlice[i], &demoSlice[i])
        pointSlice[i] = &demoSlice[i]
    }

    // 验证指针有效性
    fmt.Println("\n通过指针访问值:")
    for i, p := range pointSlice {
        fmt.Printf("pointSlice[%d] -> %+v\n", i, *p)
    }
}

输出示例(地址因运行环境而异,但彼此不同):

{str1}==++++++++++++++0x1040a120
{str2}==++++++++++++++0x1040a128
{str3}==++++++++++++++0x1040a130

通过指针访问值:
pointSlice[0] -> {name:str1}
pointSlice[1] -> {name:str2}
pointSlice[2] -> {name:str3}

⚠️ 注意事项:

总结:Go 中“取切片元素指针”的标准写法永远是 &slice[index],而非 &value;理解 range 的值拷贝语义,是避免此类陷阱的关键。