8.7. 切片: append函数的使用 与 容量问题解答

未匹配的标注
本文档最新版为 2023,旧版本可能放弃维护,推荐阅读最新版!

切片: append函数的使用

在第一节中,已经给大家讲解过切片与数组很大的一个区别就是:切片的长度是不固定的,可以向已经定义的切片中追加数据。并且也给大家简单的演示过通过append的函数,在原切片的末尾添加元素。

array :=[]int{ 1, 2,3 }
array = append ( array, 4) // 追加一个效
array = append (array, 5,6,7) // 追加多个数fmt .Println (array)

问题:可能有同学会问,如果容量不够用了,该怎么办呢?

例如有以下切片:

s:= make([]int, 5, 8)

定义了切片s,长度是5,容量是8

s := make ( []int,5,8)
fmt.Printf("len = %d,cap = %d\n", len(s), cap(s))

结果是
len = 5 , cap = 8

并且前面我们讲解过,长度是指已经初始化的空间,现在切片s没有赋值,但是默认值为0

验证如下所示:

s:=make ([]int, 5, 8)
fmt . Printf ( "len = %d,cap = %d\n", len(s),cap(s))
fmt.Println(s)

结果是:

len = 5,cap = 8[0 0 0 0 0]

元素赋值,并不是追加,所以结果的长度不变

现在开始通过append函数追加数据,如下所示:

s:=make ( []int, 5,8)
s= append (s, 1)  // 追加数据
fmt . Println(s)
fmt . Printf ( "len = %d, cap_= %d\n", len(s), cap(s) )

输出结果是:

[0 0 0 0 0 1] 
len = 6, cap = 8

由于s[0]=1是直接给下标为0的元素赋值,并不是追加,所以结果的长度不变。

下面我们继续通过append( )继续追加数据:

s := make ( [ ]int, 5,8)
s = append (s, 1)
s = append (s,2)
s =append(s,3)
fmt .Println (s)
fmt .Printf ( "len = %d, cap = d\n", len (s), cap (s))

结果是:

[0 0 0 0 0 1 2 3]
len =8,cap _= 8

追加完成3个数据后,长度变为了8,与容量相同。
那么如果现在通过append( )函数,继续向切片s中继续追加一个数据,那么容量会变为多少呢?
代码如下:

s := make ( [ ]int, 5,8)
s = append (s, 1)
s = append (s,2)
s =append(s,3)
s =append(s,4)
fmt .Println (s)
fmt .Printf ( "len = %d, cap = d\n", len (s), cap (s))

结果是:

[0 0 0 0 0 1 2 3 4]
len =9,cap = 16

追加完成一个数据后,长度变为9,大于创建切片s时的容量,所以切片s扩容,变为16.
那么切片的容量是否是以2倍容量来进行扩容的呢?
我们可以来验证一下:

双倍扩容

如果超过原来的容量,通常以2倍容量扩容

//如果超过原来的容量,通常以2倍容量扩容
s := make ( []int, 0, 1) // 容量为1
oldCap := cap (s)
for i := 0; i < 20; i++ {
    s= append (s, i)
    newCap := cap (s)
    if oldCap < newCap {
        fmt.Printf ( "cap: 8d ===> %d\n", oldcap, newCap)
        oldcap = newCap
    }
}

输出结果是:

cap: 1 ===>2
cap: 2===>4
cap: 4 ===>8
cap: 8 ===>16
cap: 16 ===>32

当容量小于1024时是按照2倍容量扩容,当大于等于1024是不是按照2倍容量扩容

但是我们修改一下循环条件看一下结果,将循环结束的条件修改的大一些,如下所示:

//如果超过原来的容量,通常以2倍容量扩容
s := make ( []int, 0, 1) // 容量为1
oldCap := cap (s)
for i := 0; i < 200000; i++ {
    s= append (s, i)
    newCap := cap (s)
    if oldCap < newCap {
        fmt.Printf ( "cap: 8d ===> %d\n", oldcap, newCap)
        oldcap = newCap
    }
}

对应的结果:

cap: 128 ===>256
cap: 256===>512 //2倍扩容
cap: 512===>1024
cap: 1024 ===>1344 //不是2倍扩容
cap: 1344 ===>1696
cap: 1696===>2368
cap: 2368 ===>3072
cap: 3072===>4096
cap: 4096===>5120
cap: 5120 ===> 6816
cap: 6816 ===>10240
cap: 10240 ===>14336

通过以上的运行结果分析:当容量小于1024时是按照2倍容量扩容,当大于等于1024是不是按照2倍容量扩容。

扩容总结

切片容量不够,自动扩容,如果超过原来的容量,通常以 2 倍容量扩容,当容量小于 1024 时是按照 2 倍容量扩容,当大于等于 1024 是不是按照 2 倍容量扩容

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~