Go-slice(Go学习笔记)

390 阅读4分钟

背景

这篇文章是我看 幼麟实验实验-Golang合辑 的学习笔记,有点类似于视频的文字版吧,该文章里的图片也是截取视频里面的,再加上自己的一些标注。这个视频合辑适合有 Go 基础的同学看哈,所以文章也一样呢!有不正确的地方欢迎大家指正呀~

slice

slice有三个部分: 1:元素存哪里 2:存了多少个元素 3:可以存多少个元素

如:声明一个整型slice var ints []int

slice的元素要存在一段连续的内存中,实际上就是个数组

变量ints由三个部分组成: data=nil:这个底层数组的起始地址,但是目前只分配了这个切片结构,还没有分配底层数组,所以这里为nil 存储个数为0 容量也为0

如果要用make的方式定义这个变量,不仅会分配这三部分结构,还会开辟一段内存作为它的底层数组。 这里,make会为ints开辟一段容纳5个整型元素的内存,还会把它们初始化为整型的默认值0。 但是,目前这个slice变量只存储了两个元素 var ints []int = make([]int, 2, 5)

可以添加元素 ints = append(ints,1) ints[0] = 1

已经存储的元素是可以安全读写的,但是超出这个范围,就属于越界访问,会发生panic

看看字符串类型的slice,但是不用make,来试试new。

new一个slice变量,同样会分配这三部分结构,但它不负责底层数组的分配,所以data=nil,len=0,cap=0 new的返回值就是slice结构的起始地址

ps := new([]string)

new的返回值就是slice结构的起始地址,所以ps就是个地址,此时这个slice变量还没有底层数组 (*ps)[0] = "eggo" 像这样的操作是不允许的

那谁来给它分配底层数组呢,append

通过append的方式添加元素,它就会给slice开辟底层数组 *ps = append(*ps, "eggo")

而字符串类型有两部分组成,一个是内容起始地址,指向字符串内容,还有一个是字节长度

接下来看看与slice密切相关的底层数组

数组:就是同种类型的元素一个挨一个的存储 int型slice,底层就是int数组 string型slice,底层就是string数组

变量arr是容量为10的整型数组,注意,数组容量声明了就不能变了 arr := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 0}

我们可以把不同的slice关联到同一个数组,就像这样,它们会公用底层数组 var s1 []int = arr[1:4] 左闭右开 容量是从1开始,到底层数组结束共有9个元素:data = [1, 2, 3], len = 3, cap = 9

var s2 []int = arr[7:] s2的元素从索引7开始知道结束:data = [7, 8, 9], len = 3, cap = 3

slice访问和修改的都是底层数组的元素 可通过append来扩大可读写的区间范围

s2 = append(s2, 10) 继续给s2添加元素的时候,这个底层数组就不能用了,得开辟新数组,原来的元素要烤过来,还要添加新元素,扩容到6:data = [7, 8, 9, 10], len = 4,cap = 6

怎么知道它要扩容到多大,到底是怎么扩容的呢?这就要看slice的扩容规则了。

ints := []int{1,2} 扩容前容量 oldCap = 2 ints = append(ints, 3,4,5) 至少扩容到 cap = 5 所以 ints 扩容后的容量newCap = 5

扩容规则: step1: 预估扩容后容量newCap 预估规则: 1、如果扩容前容量翻倍还是小于所需最小容量,那么预估容量就等于所需最小容量 2、否则再细分: (1)、如果扩容前元素个数小于1024,那就直接翻倍 (2)、如果大于等于1024,那就先扩个四分之一,也就是扩到原来的1.25倍

预估容量只是预估元素的“个数”,这么多元素,需要占用多少内存呢,这就和元素类型挂钩了

step2: newCap个元素需要多大内存 所需内存 = 预估容量 * 元素类型大小

在编程语言中,申请内存分配,并不是直接与操作系统交涉,而是和语言自身实现的内存管理模块,它会提前向操作系统申请一批内存,分成常用的规格管理起来。 我们申请内存时,它会帮我们匹配到足够大且最接近的规格

规格: 8,16,32,48

step3: 将预估申请内存匹配到合适的内存规格

之前的例子,预估容量为 5,64位以下就需要申请40字节存放扩容后的底层数组,而实际申请时会匹配到48字节 5 * 8 = 40byte

那这么大的内存能装多少元素呢? 在这个例子中,每个元素占8字节,一共能装6个