GO基本数据结构:slice
一个slice是一个数组某个部分的引用。在内存中,它是一个包含3个域的结构体,
分为3个部分:
1.指向slice的指针
2.slice的长度,长度是下标操作的上界,如x[i]中i必须小于长度
3.slice的容量,容量是分割操作的上界,如x[i:j]中j不能大于容量
数组的slice不是复制操作,而是一个新的数据结构,新的指针,x[1:3]它只是写了一个新的slice结构的属性来引用相同的存储数据
slice的扩容
其实slice在Go的运行时库中就是一个
C语言动态数组的实现,
在$GOROOT/src/pkg/runtime/runtime.h中可以看到它的定义
1 | struct Slice |
对slice进行append的操作时,slice会自动扩容
规则:
1、扩容后的大小是当前大小的2倍以上,则是新大小
1 | if newSize >= 2* oldSize { |
2、如果扩容后的大小小于当前大小的2倍,则循环以下操作:
1.当前大小小于1024,则按2倍大小增长
2.当前大小大于1024,则按1/4倍大小增长
增长后的大小超过新大小,则结束循环
1 | if newSize >= 2* oldSize { |
go协程下的slice扩容append
问题:go协程下,进行append操作,append并不是协程安全,往一个slice下添加,并发高,会出现问题
方法1,索引处理
设置一个全局slice
go协程下,不进行append,而是对全局slice,利用局部索引赋值,在for循环,go协程结束后,对其进行处理
开销比较小
方法2,channel
方法3,加锁
对append操作进行上锁,append完进行解锁
开销比较大
1 | var l sync.Mutex |
slice添加元素
追加元素
1 | a = append(a, i) |
插入元素
创建临时切片
取前2位,然后插入3,再把后几位加上
1 | var a = []int{1,2,4,5,6} |
append链式操作
1 | var a = []int{1,2,4,5,6} |
copy操作
新添加一个0,然后复制,不需要新开切片
1 | var a = []int{1,2,4,5,6} |
这种方法比较高效
1 | s = append(s, zero_value) |
slice删除元素
根据下标删除元素
1 | //删除元素 3 索引(下标) 3 |
slice反转
1 | func reverse(s []byte) []byte { |
1 | func reverseSlice (arr []int) { |