You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言遍历结构体切片时指针赋值值覆盖问题问询

嘿,这个问题我太熟了——这是Go语言range循环里一个超级容易踩的经典陷阱!

问题根源

在你的循环代码里:

for _, d := range entries {
    // ... 赋值指针的操作
}

变量d并不是每次循环都新建的!它在整个循环周期里只会被初始化一次,每次迭代只是把切片当前元素的值拷贝到d这个已经存在的变量里。换句话说,所有循环步骤里的d都是同一个内存地址。

当你执行t1 = &d.LogTime时,你拿到的其实是d这个复用变量里LogTime字段的地址。等循环跑完,d里装的是切片最后一个元素的值,那t1和t2自然都指向最后那个元素的LogTime了,这就导致你看到两个变量值一样的情况。

你找到的解决方案为啥有效?

你改成tmp := d.LogTime; t1 = &tmp是完全正确的!因为tmp是在每次循环迭代内部创建的新变量,每个tmp都有自己独立的内存空间,把它的地址赋值给t1,就不会被后续循环的d覆盖了。

还有其他两种常用方案

  • 直接用切片索引取原元素指针
    这种方式不需要拷贝值,直接操作切片里原元素的指针,效率更高:

    for i := range entries {
        d := &entries[i] // 直接取切片中第i个元素的指针
        if d.EntryType == print {
            t1 = &d.LogTime
        }
        if d.EntryType == saw {
            t2 = &d.LogTime
        }
    }
    
  • 存储值而非指针(如果业务允许)
    既然time.Time是值类型,如果你不需要保留指针的话,直接存值更简单,彻底避开指针问题:

    var t1, t2 time.Time // 改成值类型变量
    for _, d := range entries {
        if d.EntryType == print {
            t1 = d.LogTime
        }
        if d.EntryType == saw {
            t2 = d.LogTime
        }
    }
    

最后划个重点

以后用Go的range循环时,只要涉及到取迭代变量的地址,一定要警惕变量复用这个特性。要么用临时变量开辟新空间,要么直接操作切片索引的元素指针,或者干脆存值不存指针,就能避开这个坑啦!

内容的提问来源于stack exchange,提问作者Thomas Geulen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:52:49