Go中数组传参默认值拷贝,修改不影响原数组;要修改需传指针并显式解引用,如(*a)[0] = 100,且数组长度是类型一部分,[3]int与[4]int指针不兼容。

数组传参默认是全量值拷贝,改了也不生效
Go 里 [3]int 是数组,不是切片;它属于值类型,长度是类型的一部分。函数参数写成 func f(a [3]int),调用时会把整个数组(3个元素)完整复制一份——哪怕只改 a[0],原数组也完全不受影响。
- 常见错误现象:
modify(arr)函数里赋值arr[0] = 100,但调用后arr还是老样子 - 这不是 bug,是设计:Go 所有传参都是值传递,数组也不例外
- 小数组(比如
[4]int)拷贝开销小;但换成[1000000]int,一次调用就可能卡顿甚至 OOM
想改原数组?必须传指针,且解引用要显式
用 *[3]int 当参数类型,传入 &arr,才能真正操作原数组。但注意:a[0] = 100 在指针参数下会报错 cannot assign to a[0] (a is not addressable),因为 a 是指针变量,不是可寻址的数组本身。
- 正确写法是
(*a)[0] = 100,先解引用再下标赋值 -
a := *[3]int这种写法是把指针解出来赋给新变量,后续改的是副本,原数组仍不变 - 数组指针类型严格匹配长度:
*[3]int和*[4]int完全不兼容,不能混用
别拿切片当数组用,它们行为根本不同
[]int 是切片,[3]int 是数组,二者传参机制差异极大。切片传参虽也是值传递,但拷贝的是包含底层数组指针、长度、容量的三字段结构体——所以改 s[0] 能生效,而 append(s, x) 或 s = s[1:] 却不会影响原变量。
- 误把
func f(s []int)当作“数组引用传参”是常见误区;它只是共享底层数组,不是共享切片头 - 如果函数内需要扩容或重切,又希望结果反馈到调用方,必须返回新切片并重新赋值,比如
s = f(s) - 真要固定长度、确定内存布局,才用数组;日常多数场景用切片更灵活安全
性能和语义要一起权衡,不是“能用指针就一定该用”
传 *[3]int 确实避免拷贝,但代价是函数可直接修改调用方数据,容易引入隐式副作用。尤其在并发或多人协作代码中,这种修改可能破坏预期状态。
立即学习“go语言免费学习笔记(深入)”;
- 小数组(≤ 8 字节,如
[2]int)传值反而更清晰、更安全 - 大数组或需修改时才考虑指针;同时建议函数名体现意图,比如
mutateArray比processArray更明确 - 接口约束下更要小心:如果某个方法接收者用了
*[3]int,那所有调用点都得传地址,漏掉&就编译失败


















