如何在Golang中掌握数组切片长度容量_Golanglen与cap函数使用

11次阅读

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

如何在Golang中掌握数组切片长度容量_Golanglen与cap函数使用

len 和 cap 函数返回什么值

len 返回当前切片中元素的个数,cap 返回底层数组从切片起始位置到数组末尾的可用空间长度。两者都返回 int 类型,但含义不同:一个管“用了多少”,一个管“还能加多少”。比如 make([]int, 3, 5) 创建的切片,len3cap5;此时追加一个元素不会触发扩容,再加一个就会——因为第 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=%dn", 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 只在 appendmake 时参与内存分配决策。

立即学习go语言免费学习笔记(深入)”;

  • 想预留空间用 make([]T, 0, n),不是 make([]T, n)
  • 想检查能否无扩容追加,应写 if len(s)+1 ,而不是 if len(s) —— 后者在 len==cap 时为 false,但此时仍可安全赋值(只要不超 len
  • 打印调试时同时输出 lencap&slice[0] 地址,比单看数字更容易发现共享问题

底层数组共享和扩容时机是隐式的,lencap 看似简单,但一旦涉及并发写入、子切片传递或内存优化,就很容易掉进指针别名或意外扩容的坑里。

text=ZqhQzanResources