
Go 语言中数组是值类型,对指针解引用(*p)会创建原数组的完整副本,修改副本不会影响原始数组;若需共享底层数据,应使用切片(如 t[:])而非复制整个数组。
go 语言中数组是值类型,对指针解引用(`*p`)会创建原数组的完整副本,修改副本不会影响原始数组;若需共享底层数据,应使用切片(如 `t[:]`)而非复制整个数组。
在 Go 中,理解数组([N]T)与切片([]T)的根本区别,是避免此类困惑的关键。数组是值类型——其大小固定、内存连续,且每次赋值或传参时都会发生完整拷贝。这与 C 或 C++ 中“数组名即指针”的语义截然不同。
以问题中的代码为例:
var t [5]int // t 是一个值:5个 int 的连续内存块 p := &t // p 是指向 t 的指针,类型为 *[5]int x := *p // 关键!此处执行解引用:将 t 的全部 5 个元素逐字节复制到新内存,x 是一个独立的 [5]int 值 x[0] = 4 // 修改的是 x 的副本,与 t 完全无关
尽管 p 和 t 的地址一致(p 指向 t),但 x := *p 并非“获取引用”,而是一次深拷贝操作。x 拥有自己独立的内存空间(即使 printType 显示地址格式相似,实际 x 的地址与 t 不同),因此对 x[0] 的修改自然不会反映到 t 上。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
✅ 正确做法:使用切片实现共享底层数据
切片是引用类型,包含指向底层数组的指针、长度和容量。要让修改生效,应将数组转换为切片:
var t [5]int p := &t s := t[:] // s 类型为 []int,底层数据与 t 共享 s[0] = 4 // ✅ 直接修改 t[0] fmt.Println(t) // 输出: [4 0 0 0 0]
⚠️ 注意事项:
立即学习“go语言免费学习笔记(深入)”;
-
&t是*[5]int,而&t[0]是*int;二者语义完全不同,不可混用; -
t[:]是最安全、最惯用的“数组转切片”方式,等价于t[0:len(t)]; - 若必须通过指针修改原数组,请直接通过指针索引:
(*p)[0] = 4(此时不产生副本,直接写入t的内存)。
总结:Go 中没有“数组引用”概念;数组复制成本高且隐式,应主动选择切片来表达共享意图。这是 Go 强调显式性与内存安全的设计体现。

















