讲讲go切片slice

首先,切片是什么?
切片slice是由三部分组成,类似于结构体
1.底层数组的地址(data)
2.存了多少个元素(len)
3.可以存多少个元素(cap)

举个例子

var slice []int

在这里插入图片描述slice元素要存在一段连续的内存中,实际上就是个数组。
data就是这个底层数组的起始地址,但目前只分配了切片结构,还没有分配底层数组,所以这里为nil,存储个数为0,容量也为0.


如果通过make的方式定义

var slice []int = make([]int, 2, 5)

在这里插入图片描述
开辟了一段容纳5个int元素的内存作为它的底层数组,初始化为0.
这样data就指向了指定数组的地址了,当前存了2个元素,容量为5.


现在追加一个元素看看

slice = append(slice, 1)

在这里插入图片描述
已经存了2个,所以追加是在第三个,也就是slice[2],len就修改为3.
注意已经存储的元素是可以安全读写的,也就是len的长度内。一旦超出这个范围,就属于越界访问了,会发生panic,比如slice[3] = 1。


这次来看看字符串类型的slice,不用make,来试试new

p := new([]string)

在这里插入图片描述

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

*p = append(*p, "hello")

在这里插入图片描述
通过append添加元素,给slice开辟底层数组,需要容纳一个字符串元素的数组,而字符串类型有俩部分组成,一个是起始地址,指向字符串内容,还有一个是字节长度


数组跟切片

arr := [10]int{0,1,2,3,4,5,6,7,8,9}
var s1 []int = arr[1,4]
var s2 []int = arr[7:]

在这里插入图片描述
定义变量arr整形数组,注意数组容量声明了就不能修改,可以把不同的slice关联在同一个数组上,共用底层数组.
s1的元素是arr索引1到4,左闭右开,这三个元素就添加到s1中了,但是容量是从data这里开始到底层数组结束共有9个元素。
s2的元素同理s1,元素为3,容量也是3.

如果给s2再添加元素会怎样?那这个arr底层数组是不能用了,得开辟新数组。

s2 = append(s2, 10)

在这里插入图片描述
拷贝原来的元素,添加新元素,元素个数改为4,容量扩到6.


扩容机制
这里就出现了问题,只给s2添加了一个元素,容量怎么从3变成6了?
那就要看slice的扩容规则了。
预估判断:
如果扩容前容量翻倍还是小于所需最小容量,那么预估容量就等于所需最小容量
否则如果扩容前元素个数小于1024,那就翻倍,如果大于等于1024,那就扩个1.25倍(这个1.25倍貌似有点不对,大家翻看源码看看)

if oldcap * 2 < cap {
	newcap = cap
} else {
	if oldlen < 1024 {
		newcap = oldcap * 2
	} else {
		newcap = oldcap * 1.25
	}
}	

第一步:预估扩容后的容量

s := []int{1,2}   //扩容前oldcap = 2
s = append(s,3,4,5) //预估扩容到5

2 * 2 < 5
所以s容量2翻倍了还是小于5,那预估容量就是5

第二步:预估容量只是元素个数,那需要占用多少内存呢?
用预估容量*元素类型大小,得到就是所需内存大小了。5 * 8 = 40
但不是直接分配这么多就可以了,go的内存管理模块已经申请一批内存.0, 8, 16, 32, 48, 64, 80, 96, 112, 128…
会去匹配足够大并最接近的大小,也就是48。

第三步:取实际容量个数
在上一步匹配到内存48字节可以装多少个元素呢?内存大小/元素类型大小
48 / 8 = 6
这个6就是扩容后的容量了

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值