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,直到满足容量需求。

slice编程技巧

参考