len 返回切片当前元素个数,cap 返回底层数组从切片起始到末尾的可用长度;小切片扩容约1.25倍,大切片(cap≥1024)每次增长约1.25倍,新cap由运行时决定不可预测。

len 和 cap 函数返回什么值
len 返回当前切片中元素的个数,cap 返回底层数组从切片起始位置到数组末尾的可用空间长度。两者都返回 int 类型,但含义不同:一个管“用了多少”,一个管“还能加多少”。比如 make([]int, 3, 5) 创建的切片,len 是 3,cap 是 5;此时追加一个元素不会触发扩容,再加一个就会——因为第 5 个位置是最后一个可用索引。
切片扩容时 cap 怎么变
当用 append 向切片添加元素导致容量不足时,Go 运行时会分配新底层数组。扩容策略不是固定倍增,而是分段处理:
– 小切片(cap )按 2 倍增长;
– 大切片(cap >= 1024)每次增长约 1.25 倍;
– 实际新 cap 值由运行时内部算法决定,不可预测,也不能依赖。
slice := make([]int, 0, 1)
for i := 0; i < 6; i++ {
slice = append(slice, i)
fmt.Printf("len=%d, cap=%d\n", len(slice), cap(slice))
}
// 输出可能为:len=1,cap=1 → len=2,cap=2 → len=3,cap=4 → len=4,cap=4 → len=5,cap=8 → len=6,cap=8
修改底层数组会影响哪些切片
多个切片共用同一底层数组时,只要它们的底层指针和长度范围有重叠,修改其中一个切片的元素就可能影响另一个。判断是否共享底层数组不能只看 len/cap,而要看 unsafe.Pointer(&slice[0]) 是否相等,以及内存区间是否交叉。
- 用
slice[i:j:k]形式截取可显式限制新切片的cap,避免意外写入原底层数组后半部分 - 用
append(slice[:0:0], src...)可强制复制一份新底层数组,彻底隔离 - 直接赋值
s2 := s1不会复制底层数组,只是复制头信息(指针、len、cap)
常见误用:把 cap 当作“最大允许长度”来检查
cap 不是安全边界,越界写入(如 slice[cap] = x)会 panic:panic: runtime error: index out of range [5] with length 5。切片合法索引范围永远是 0 ,cap 只在 append 或 make 时参与内存分配决策。
立即学习“go语言免费学习笔记(深入)”;
- 想预留空间用
make([]T, 0, n),不是make([]T, n) - 想检查能否无扩容追加,应写
if len(s)+1 ,而不是if len(s) —— 后者在len==cap时为 false,但此时仍可安全赋值(只要不超len) - 打印调试时同时输出
len、cap和&slice[0]地址,比单看数字更容易发现共享问题
len 和 cap 看似简单,但一旦涉及并发写入、子切片传递或内存优化,就很容易掉进指针别名或意外扩容的坑里。









