
go 语言中数组是值类型,赋值时会完整复制所有元素到新内存空间,属于深拷贝;修改副本不会影响原数组,这与引用类型的 slice 截然不同。
go 语言中数组是值类型,赋值时会完整复制所有元素到新内存空间,属于深拷贝;修改副本不会影响原数组,这与引用类型的 slice 截然不同。
在 Go 中,数组(如 [2][3]int)的底层实现是连续、固定大小的内存块,不包含任何指针或间接引用——它本身就是数据本身。这意味着每次对数组变量进行赋值(包括子数组赋值,如 a[0] = a[1]),编译器都会执行按字节逐位复制(bitwise copy),将源数组的全部内容完整复制到目标数组的独立内存区域中。
以问题中的二维数组为例:
var a [2][3]int a[0][0] = 55; a[0][1] = 56; a[0][2] = 57 a[1][0] = 65; a[1][1] = 66; a[1][2] = 67
此时 a 在内存中占据连续的 6 个 int 单元(假设 int 为 8 字节,则共 48 字节),布局为:
[55 56 57 | 65 66 67] ↑a[0]↑ ↑a[1]↑
执行 a[0] = a[1] 后,Go 将 a[1] 的三个 int 值(65, 66, 67)完整复制到 a[0] 对应的内存位置。结果内存变为:
[65 66 67 | 65 66 67] ↑a[0]↑ ↑a[1]↑
注意:a[0] 和 a[1] 各自拥有独立的内存空间。后续修改 a[0][0] 不会影响 a[1][0],反之亦然。这是典型的值语义(value semantics),也是 Go 数组安全性的基础。
✅ 正确理解要点:
- 所有数组类型(无论维度)都是值类型;
- 数组赋值、函数传参、结构体字段嵌入等场景下,均发生深拷贝;
- 深拷贝开销与数组大小成正比,因此大数组应谨慎使用,必要时可改用
*[N]T指针或[]T切片(但需注意切片是浅拷贝,仅复制 header)。
⚠️ 对比提醒:
切片([]int)则完全不同——它是一个三字段结构体(ptr, len, cap),赋值时只复制这三个字段(即浅拷贝),底层数据仍共享同一底层数组。因此 s1 := s2 后修改 s1 元素可能影响 s2,而 a1 := a2(a1, a2 为 [N]T)则绝对隔离。
总结:Go 数组的“深拷贝”不是语言层面的模拟行为,而是由其值类型本质和内存布局决定的底层事实——没有指针,只有数据;没有共享,只有复制。










