Go中数组传参复制全部数据,切片只传指针、len和cap三个字段;大数组不加传参是性能雷区;append可能创建新底层数组,需用s=append(*s,x)修改原切片;初始化时指定cap可避免多次扩容;len==cap可判断是否即将扩容;共享底层数组易引发隐蔽bug,可用copy或append([]T(nil), src...)深拷贝;固定长度场景数组更安全高效。

数组传参会复制全部数据,切片只传三个字段
Go 里 func f(arr [1000]int) 每次调用都拷贝 1000 个整数;而 func f(s []int) 只传一个指针 + 两个整数(len 和 cap),开销几乎固定。
- 大数组传参不加
*就是性能雷区,尤其在循环或高频调用中 - 切片传参看似“引用”,但
append后返回的新切片可能指向新底层数组,原变量不会自动更新 - 如果真要修改原切片长度,必须用指针:
func extend(s *[]int, x int),再通过*s = append(*s, x)
初始化时没设 cap,append 多次扩容很慢
写 s := []int{1,2,3} 或 s := make([]int, 3),初始 cap 就等于 len(都是 3)。一旦 append 第 4 个元素,就得分配新数组、复制旧数据——连续追加 1000 个元素,可能触发 10+ 次内存重分配。
- 已知大概数量时,直接指定容量:
s := make([]int, 0, 100),后续 100 次append都不会扩容 -
cap不是上限,只是“当前底层数组还能塞多少”,len才是当前可读写的长度 - 用
len(s) == cap(s)判断是否即将扩容,比盲目append更可控
多个切片共享底层数组,改一个会影响另一个
这是最隐蔽的 bug 来源。比如 a := arr[2:5] 和 b := arr[4:7],它们重叠在 arr[4] 上;改 a[2] 实际就是改 b[0]。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 截取切片时注意范围,避免无意共享:用
copy(dst, src)显式复制数据,得到完全独立的副本 - 函数返回切片时,若底层数组来自入参(如
return data[lo:hi]),调用方可能意外修改你内部状态 - 敏感场景(如配置解析、网络包拆解)建议用
append([]byte(nil), src...)强制深拷贝
该用数组的地方硬用切片,反而增加间接层
数组不是废柴。当长度固定、语义明确、且需做 map key 或 struct 字段时,数组更合适。比如 [32]byte 常用于哈希值,[4]byte 表示 IPv4 地址,[16]byte 是 UUID。
立即学习“go语言免费学习笔记(深入)”;
- 数组类型包含长度,
[3]int和[4]int是不同类型,编译期就能防错 - 小数组(≤ 几个元素)作为结构体字段,比切片更省内存(无指针、无额外头信息)
- 别为了“统一风格”把所有固定结构都改成切片——多一层指针跳转,少一点确定性
len/cap 和共享关系;数组笨重,但边界清晰、零歧义。选哪个,取决于你愿不愿意为灵活性多操一份心。

















