golang切片append

golang中的数组和其他语言的数组概念差别不大。golang的数组是定长的,初始化之后大小不能发生改变。需要使用变长数组的场景,就需要引入切片
切片是某个数组的引用,切片的容量可以动态变化

切片

切片中的几个概念:

  • 元素(element):指切片中的数据
  • 长度(len):切片中元素的个数
  • 容量(cap):切片的最大元素个数

append

golang中对append的说明如下:

The append built-in function appends elements to the end of a slice. If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated. Append returns the updated slice. It is therefore necessary to store the result of append, often in the variable holding the slice itself

里面的关键信息在于:append的时候,如果切片的容量充足,会对切片重新切片(切片指向的是同一个底层数组),如果容量不足,会分配新的底层数组,并且复制里面的数据

下面通过代码测试一下(golang版本:go1.16,4)

import "log"

func main() {
    a := [3]string{"A", "B", "C"}
    b := a[1:3]
    log.Printf("a is %v,b is %v, len(b) is %d, cap(b) is %d", a, b, len(b), cap(b))
    b[0] = "D"
    log.Printf("a is %v,b is %v, len(b) is %d, cap(b) is %d", a, b, len(b), cap(b))
}

运行结果

2021/09/16 09:25:02 a is [A B C],b is [B C], len(b) is 2, cap(b) is 2
2021/09/16 09:25:02 a is [A D C],b is [D C], len(b) is 2, cap(b) is 2

在此例中,a是一个数组,b是一个切片,容量为2,长度为2。b[0]指向a[1]。对b进行修改会影响a

增加元素

golang中通过append往切片中追加元素

b = append(b,"D")
b[0] = "E"

运行结果

2021/09/16 09:52:29 a is [A D C],b is [E C D], len(b) is 3, cap(b) is 4

执行append之后,b中将会有3个元素,超过了原有的cap,b需要扩容。扩容后容量由2变为了4,并且指向了新的底层数组,对b进行修改,不再影响a

删除元素

golang没有提供直接删除切片元素的接口,删除元素通常也是由append实现

package main

import "log"

func main() {
    a := [3]string{"A", "B", "C"}
    b := a[1:3]
    log.Printf("a is %v,b is %v, len(b) is %d, cap(b) is %d", a, b, len(b), cap(b))

    //删除元素
    b = append(b[:0], b[1:]...)
    log.Printf("a is %v,b is %v, len(b) is %d, cap(b) is %d", a, b, len(b), cap(b))
}

运行结果

2021/09/16 10:04:43 a is [A B C],b is [B C], len(b) is 2, cap(b) is 2
2021/09/16 10:04:43 a is [A C C],b is [C], len(b) is 1, cap(b) is 2

append之后,b的元素只剩一个C,小于b原有的容量2,所以b的容量不变(不会缩容),b的底层数组仍然是a,b[0]指向a[1]。b[0]变成了C,所以a[1]也变成了C

切片的切片

表面上看,上面的解释已经很合理了,其实遗漏了一个隐藏的细节

    b = append(b[:0], b[1:]...)

append传参传入的是b[:0],是一个新的切片,append中判断是否需要扩容应该是根据b[:0]的容量大小而不是b的容量大小。那么b[:0]的容量是多少?
写段代码测试一下

    c := b[:0]
    log.Printf("c is %v,len(c) is %d, cap(c) is %d", c, len(c), cap(c))
    d := b[1:]
    log.Printf("d is %v,len(d) is %d, cap(d) is %d", d, len(d), cap(d))

运行结果

2021/09/16 13:01:09 c is [],len(c) is 0, cap(c) is 2
2021/09/16 13:01:09 d is [C],len(d) is 1, cap(d) is 1

从结果中可以看出,c从b[0]开始切片,容量是2(0->数组末尾);d从b[1]开始,容量是1(1->数组末尾)

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 线性结构是计算机最常用的数据结构之一。无论是数组(arrary)还是链表(list),在编程中不可或缺。golan...
    _二少爷阅读 6,667评论 5 13
  • 总目录:https://www.jianshu.com/p/e406a9bc93a9 Golang - 子目录:h...
    寒暄_HX阅读 417评论 0 0
  • 切片(slice)是 Golang 中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合。切片是围绕动态...
    51reboot阅读 28,721评论 2 10
  • 切片(slice)是 Golang 中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合。切片是围绕动态...
    小孩真笨阅读 1,132评论 0 1
  • 本文系第十二篇Golang语言学习教程上一节学习了golang数组的知识,这节开始学习切片的概念应用;首先来看多维...
    xunk1900阅读 1,211评论 0 2