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
相关产品推荐
相关产品推荐

