应优先使用切片而非数组;数组仅适用于编译期长度确定且不可变的场景,如结构体字段、map key、硬件交互或值语义拷贝;切片扩容有性能成本,数组固定尺寸换取内存布局可预测性与并发安全性。

Sum 函数如果只接收 [5]int,就无法处理长度为 3 或 7 的整数集合——这不是设计缺陷,而是数组类型本身不可变的硬约束。绝大多数业务场景下,你应该直接用切片。
什么时候必须用数组?
只有当长度在编译期完全确定、且绝不能变化时才考虑数组:
- 作为结构体字段固定尺寸(如 type IPv4 [4]byte)
- 用作 map 的 key(map[[4]byte]string 合法,map[][]byte 不合法)
- 底层协议或硬件交互要求精确字节对齐(如加密哈希输出 [32]byte)
- 需要值语义拷贝且明确控制内存布局(比如避免意外共享底层数组)
make([]int, 0, 5) 和 []int{} 的区别
两者都创建空切片,但容量不同:
- []int{}:长度 0,容量 0,首次 append 必触发分配
- make([]int, 0, 5):长度 0,容量 5,前 5 次 append 不分配新内存
- 容量预估不准反而浪费空间;过度依赖 make 可能掩盖真实增长模式
- 若后续要大量追加,用 make 预分配更高效;若只是临时拼接,直接字面量更清晰
切片截取后修改引发的共享坑
这是最常被忽略的隐性 bug 来源:
- arr := [5]int{1,2,3,4,5} → s1 := arr[1:3] 和 s2 := arr[2:4] 共享同一底层数组
- 修改 s1[1] = 99 会同时改掉 s2[0],因为它们指向 arr[2] 这个位置
- 修复方法:需要隔离时用 copy 构造新底层数组:newS := make([]int, len(s1)); copy(newS, s1)
- 千万别以为 append(s1, x) 就安全——如果没扩容,仍共享原数组;扩容后才断开
函数参数该传 []T 还是 *[N]T?
几乎总是选前者:
- func f(s []int):自然支持任意长度,底层指针+长度+容量三元组传递,零拷贝
- func f(p *[5]int):强制传入地址,调用方必须显式取地址 &a,且类型严格绑定长度
- 数组指针仅在极少数场景有用:需原地修改大数组且明确长度(如图像像素批量处理),否则就是自缚手脚
- 如果真需要固定长度约束,用类型别名 + 接口约束更柔性,例如 type Fixed5 [5]int,再定义 func Process(f Fixed5)
切片的“动态”不是免费的——每次扩容都涉及内存分配与旧数据复制,而数组的“固定”也不是死板的,它换来的是可预测的内存布局和并发安全的值拷贝。选哪个,取决于你是否真的需要那个“变”字。


















