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

Go语言结构体切片内存原理:为何两次赋值结果不同?

Go语言值切片与指针切片的内存差异解析

我们直接从内存布局的角度拆解两段代码的差异:

第一段代码(值类型切片)

type TreeNode struct {
    Val int
    Left *TreeNode
    Right *TreeNode
}

queue:=[]TreeNode{TreeNode{}}
node:=TreeNode{Val: 1}
pre:=queue[len(queue)-1]
pre.Left = &node

内存细节:

  • 切片queue本身是一个结构体,假设它的内存地址是0x1001,里面存储三个核心字段:
    • 指向底层数组的指针:0x2000
    • 切片长度:1
    • 切片容量:1
  • 底层数组起始地址0x2000中,直接存储的是TreeNode{}实例的完整副本(原始实例地址假设为0x3001,副本内容为Val=0、Left=nil、Right=nil)。
  • 执行pre := queue[len(queue)-1]时,会把底层数组0x2000处的TreeNode实例再复制一份到pre的内存地址(比如0x4001)。此时pre和queue[0]是两个完全独立的TreeNode实例。
  • 最后pre.Left = &node仅修改了0x4001处实例的Left字段,让它指向node的地址0x5001,但底层数组0x2000处的实例Left字段依然是nil,所以queue[0].Left保持nil状态。

第二段代码(指针类型切片)

type TreeNode struct {
    Val int
    Left *TreeNode
    Right *TreeNode
}

queue:=[]*TreeNode{&TreeNode{}}
node:=&TreeNode{Val: 1}
pre := queue[len(queue)-1]
pre.Left = node

内存细节:

  • 切片queue的内存地址还是0x1001,里面的三个核心字段:
    • 指向底层数组的指针:0x2000
    • 切片长度:1
    • 切片容量:1
  • 底层数组起始地址0x2000中,存储的是一个指针值:0x3001(该指针指向&TreeNode{}创建的实际TreeNode实例,内容为Val=0、Left=nil、Right=nil)。
  • 执行pre := queue[len(queue)-1]时,复制的是底层数组里的指针0x3001到pre变量,此时pre和queue[0]指向同一个TreeNode实例(地址0x3001)。
  • 最后pre.Left = node直接修改了0x3001处TreeNode实例的Left字段,让它指向node的地址0x5001。因为queue[0]的指针始终指向0x3001,所以queue[0].Left会同步变为非nil值。

内容的提问来源于stack exchange,提问作者Tian Gao

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 01:17:33