Go中数组传参是值拷贝,修改不影响原数组;切片传参共享底层数组,修改会影响原切片。数组可作map键和==比较,切片不可。切片截取可能意外共享内存,需显式copy隔离。

数组传参后修改不影响原数据,但切片会
这是最常被忽略的语义差异:Go 中 arr [3]int 传入函数时,函数内所有操作都作用在副本上;而 s []int 传入后,s[0] = 100 会直接改到底层数组,原切片可见变化。
容易踩的坑:
- 误以为切片传参是“安全隔离”的,结果多个函数悄悄共享同一底层数组
- 把大数组(比如
[1024]byte)直接当参数传,导致栈溢出或性能下降 - 想避免共享又没用
copy或重新make,只靠append并不能切断关联
len 和 cap 不是一回事,扩容行为全看 cap
len(s) 是当前能访问的元素个数,cap(s) 是从起始位置到底层数组末尾还能塞多少元素——不是“剩余空间”,而是“不换底层数组的前提下最多能 append 多少”。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
-
s := []int{1,2,3}→len=3,cap=3,再append必然触发扩容,底层数组大概率更换 -
s := make([]int, 0, 5)→len=0,cap=5,前 5 次append都复用同一块内存,无拷贝开销 - 高频追加场景(如日志缓冲、解析临时数据),优先用
make显式指定cap,避免多次 realloc
数组能做 map 键和 == 比较,切片不能
因为数组是值类型且长度固定,编译器可生成确定的哈希和比较逻辑;切片含指针,内容可能随时变动,Go 禁止直接比较或作 map 键。
典型使用场景:
-
[32]byte存 SHA256 哈希值 → 可直接当 map key 或用==判断相等 -
[3]uint8表示 RGB 颜色 → 可比较、可排序、可序列化为固定结构 - 想用切片做类似事?必须手动转成数组(如
colorArr := [3]uint8{r,g,b})或用bytes.Equal
切片截取可能意外共享底层数组
s1 := arr[1:3] 和 s2 := arr[2:4] 若来自同一数组,它们在 arr[2] 处重叠——改 s1[1] 就等于改 s2[0]。
这不是 bug,是设计使然,但极易引发隐蔽问题:
- 返回函数内部切片时,若基于局部数组创建(如
func f() []int { a := [5]int{}; return a[:3] }),实际返回的是指向栈内存的指针,运行时崩溃风险极高 - 从大缓冲区中反复截取小切片用于网络包解析,若未及时
copy隔离,旧包数据可能被后续包覆盖 - 安全做法:需要独立副本时,显式
copy(dst, src)或append([]T(nil), src...)


















