从源码理解Go:slice
2016-11-15
slice的内部结构 #
一个slice本质上是一个数组的某个部分的引用。在go runtime/slice.go源码中定义了slice的结构:
1type slice struct {
2 array unsafe.Pointer
3 len int
4 cap int
5}
可以看到在Go的内部,slice是一个包含3个字段的结构体:
- array: 指向slice第一个元素的指针
- len: slice的长度,长度是索引操作的上届,
s[i] i<len(s)
- cap: slice的容量,容量是分割操作的上届,
s[i:j] j<=cap(s)
slice扩容 #
当对slice进行append的操作时,当容量不够时会引起slice的扩容:
1func growslice(et *_type, old slice, cap int) slice {
2 ......
3 newcap := old.cap
4 doublecap := newcap + newcap
5 if cap > doublecap {
6 newcap = cap
7 } else {
8 if old.len < 1024 {
9 newcap = doublecap
10 } else {
11 for newcap < cap {
12 newcap += newcap / 4
13 }
14 }
15 }
16 ......
17 return slice{p, old.len, newcap}
18}
从以上源码可以看出在扩容时:
- 如果容量需求大于原cap的两倍以上,则扩容后容量即为需求的容量
- 否则:
- 如果原来的len小于1024,则扩容后的cap为原cap的两倍。即按原cap 2倍增长扩容
- 如果原来的len大于等于1024,按1/4增长计算新的cap,直到满足容量需求。