数组传参时被完整复制,原数组不受影响;切片仅复制header,修改可能影响原底层数组,共享底层数组时需警惕副作用。

为什么函数传参时数组会“失效”,而切片不会
因为数组是值类型,传参时整个内存块被复制;切片是引用类型,只复制 slice header(指针+len+cap),底层数据仍在原处。
- 修改传入的
[5]int参数,原数组完全不受影响 - 修改传入的
[]int参数,只要没触发扩容,append或索引赋值都会反映到原始底层数组上 - 注意陷阱:多个切片共享同一底层数组时,
s1[0] = 100可能意外改掉s2[0]—— 这不是 bug,是设计使然
make([]T, len, cap) 的三个参数怎么配才不踩坑
初学者常误以为 cap 是“预留空间上限”,其实它是切片能向右扩展的最大长度,且直接影响后续 append 是否触发扩容。
-
make([]int, 3)→len=3,cap=3:第 4 次append必定分配新底层数组 -
make([]int, 3, 8)→len=3,cap=8:还能追加 5 个元素而不 realloc - 容量不足时扩容策略:小切片(
cap )翻倍;大切片按 1.25 倍增长 —— 不可控,提前预估更稳
从数组创建切片时,arr[1:4] 的容量到底是多少
切片表达式 arr[i:j] 的容量不是原数组长度,而是 len(arr) - i。这是最容易算错的地方。
- 给定
arr := [6]int{0,1,2,3,4,5},s := arr[2:4]→len=2,cap=4(因为6 - 2 = 4) - 这意味着
s最多还能向右扩展 2 个元素:s = s[:4]合法,s = s[:5]panic:index out of range - 若需隔离底层数组避免副作用,用
append([]int(nil), s...)或copy创建独立副本
什么场景下必须用数组,而不是切片
不是“不能用数组”,而是多数业务逻辑不需要它;但以下情况绕不开:
立即学习“go语言免费学习笔记(深入)”;
- 定义固定长度的结构体字段,如
type IPv4 [4]byte—— 数组长度是类型一部分,可做 map key - 高性能计算中对齐访问,如 SIMD 处理像素矩阵
[1920x1080]uint8,栈上分配、零拷贝 - 常量集合声明:
const days = [7]string{"Sun", "Mon", ..., "Sat"},编译期确定,无运行时开销 - 切片无法替代数组的核心点:数组长度参与类型系统,
[3]int和[4]int是不同类型;切片[]int则无视长度
真正难的不是记住区别,而是意识到:当你写 var data []int 时,你拿到的只是一个轻量句柄;而它的底层数组可能正被五个 goroutine 同时读写——这时 cap、共享与拷贝,就不再是理论问题了。










