在切片长度小于1024时会扩容为原来的2倍,超过1024扩容为原来的1.25倍if cap > doublecap内存对齐
func growslice(et *_type, old slice, cap int) slice {
    // ……
    newcap := old.cap
    doublecap := newcap + newcap
    if cap > doublecap {
        newcap = cap
    } else {
        if old.len < 1024 {
            newcap = doublecap
        } else {
            for newcap < cap {
                newcap += newcap / 4
            }
        }
    }
    // ……
    //内存对齐操作
    capmem = roundupsize(uintptr(newcap) * ptrSize)
    newcap = int(capmem / ptrSize)
}

看两个例子吧:

例1:

func main() {
    s := []int{1,2}
    s = append(s,4)
    s = append(s,5)
    s = append(s,6)
    fmt.Printf("len=%d, cap=%d",len(s),cap(s))
}
len=5, cap=8

例2

func main() {
    s := []int{1,2}
    s = append(s,4,5,6)
    fmt.Printf("len=%d, cap=%d",len(s),cap(s))
}
len=5, cap=8
growslice
满足源码中第一个 if 条件6
len=5, cap=6

例3:

func main() {
    s := []int{1,2,3,4,5}
    s = append(s,6,7)
    fmt.Printf("len=%d, cap=%d",len(s),cap(s))
}
len=7, cap=10

懵逼了没?崩溃了没?
为了避免困惑,我们来总结一下吧:

slice扩容机制:

>
A = append(A,B...)
newcap:=roundupsize(len(A)+len(B))

新旧长度之和,即最终slice长度

<=

最容易忽视的的细节,再强调一遍:

slice在append时,必须关注最终slice的长度是否超过原容量的2倍

  1. 如果不是,那么就按最开始的结论。
  2. 如果是,则容量就变为新slice的容量。

最后,执行内存对齐操作,这一步是一定不能少的!

0、1、2、4、6、8、10、12、14、16、18、20 ....

最最后,来个小练习:

2+9=1112
func main() {
    s := []int{1,2}
    s = append(s,1,2,3,4,5,6,7,8,9)
    fmt.Printf("len=%d, cap=%d",len(s),cap(s))  //len=11, cap=12 
}

  1. 扩容为2倍,正好能放下
func main() {
    s := []int{1,2}
    s = append(s,3,4)
    fmt.Printf("len=%d, cap=%d",len(s),cap(s)) //len=4, cap=4
}
  1. 扩容为2倍,能放下而且还有空余
func main() {
    s := []int{1,2,3}
    s = append(s,4,5)
    fmt.Printf("len=%d, cap=%d",len(s),cap(s)) //len=5, cap=6 ,
}
  1. 新切片长度为0,容量不为0,不进行扩容
func main() {
    s := []int{1,2,3}
    s1 := make([]int,0,4)//len=0 cap=4
    s = append(s,s1...)
    fmt.Printf("len=%d, cap=%d",len(s),cap(s)) //  len=3, cap=3,
}

5.新切片长度不为0时

func main() {
    s := []int{1,2,3}
    s1 := make([]int,4,4)//len=0 cap=4
    s = append(s,s1...)
    fmt.Printf("len=%d, cap=%d",len(s),cap(s)) //len=7, cap=8
}

示例4、5说明是按被追加切片的长度(而不是容量)来计算扩容的。

以上示例是针对长度小于1024的情况,大于1024的情况同样适用。