因为Go中数组是值类型,传参时会复制整个数组,函数内修改不影响原数组;需用数组指针(*[3]int)或切片([]int)才能修改原数据。

为什么直接传数组无法修改原数组
Go 语言中,array 是值类型。当你把一个数组(比如 [3]int)作为参数传给函数时,实际上传的是整个数组的副本。函数内部对它的任何修改,都不会影响调用方的原始数组。
常见错误现象:
func modify(arr [3]int) {
arr[0] = 999
}
a := [3]int{1, 2, 3}
modify(a)
// a 还是 [1 2 3],没变
这不是 bug,是 Go 的设计选择:数组大小固定、可比较、适合栈上分配。但这也意味着——想改原数组,必须绕过值拷贝。
用指针传递数组:明确指定长度和类型
最直接的方式是传指向数组的指针,比如 *[3]int。这时函数接收的是地址,解引用后可直接写原内存。
- 必须写明数组长度(
[3]),因为[3]int和[4]int是完全不同的类型 - 调用时需用
&a取地址,不能漏掉& - 函数内通过
(*arr)[i]或更常见的arr[0](Go 允许对数组指针直接下标访问)操作
实操示例:
func modifyPtr(arr *[3]int) {
arr[0] = 999 // 等价于 (*arr)[0] = 999
}
a := [3]int{1, 2, 3}
modifyPtr(&a)
// a 现在是 [999 2 3]
更常用的是切片:隐式指针 + 灵活长度
绝大多数场景下,你真正需要的不是“修改固定长度数组”,而是“修改一段连续数据”。这时应优先用 []int(切片),它底层包含指向底层数组的指针、长度和容量。
立即学习“go语言免费学习笔记(深入)”;
切片是引用类型(本质是结构体,含指针字段),传参时只拷贝这个小结构体,不影响语义上的“可修改原数据”。
- 函数签名更简洁:
func modifySlice(s []int),无需写死长度 - 调用方直接传
a[:](从数组转切片)或原生切片变量 - 注意:仅修改元素值可生效;但
append可能导致底层数组扩容,此时原数组不受影响
示例:
a := [3]int{1, 2, 3}
modifySlice(a[:]) // 传切片视图
// a 被修改了
func modifySlice(s []int) {
if len(s) > 0 {
s[0] = 999 // ✅ 影响原数组
}
}
容易踩的坑:混淆数组指针和切片,以及越界行为
新手常把 *[3]int 当成“类似 C 的 int*”,结果发现不能用 len()、不能遍历、甚至传错类型。
-
*[3]int不是切片,不能直接用range,也不能调用len()或cap()—— 必须先解引用:len(*arr) - 误写成
func f(arr *[3]int)却传&[]int{1,2,3}:类型不匹配,编译失败 - 用切片时以为
append总是修改原数组:其实当容量不足时会分配新底层数组,原数组不变 - 数组指针在结构体字段中要小心:
type T struct { Data *[1024]byte }会把整个 1KB 数组塞进结构体,通常应改用[]byte或*[1024]byte配合make分配
复杂点在于:Go 没有“动态数组”原生类型,数组和切片语义分离。选哪种,取决于你是否需要编译期长度检查、是否涉及 cgo、是否追求极致栈分配——大多数业务代码,用切片就够了,别硬套数组指针。










