GoLang中的切片扩容机制[5]int是数组go语言扩容,而[]int是切片 。二者看起来相似go语言扩容,实则是根本上不同的数据结构 。
切片的数据结构中,包含一个指向数组的指针array,当前长度len , 以及最大容量cap。在使用make([]int, len)创建切片时,实际上还有第三个可选参数cap,也即make([]int, len, cap)。在不声明cap的情况下 , 默认cap=len。当切片长度没有超过容量时 , 对切片新增数据,不会改变array指针的值 。
当对切片进行append操作,导致长度超出容量时 , 就会创建新的数组,这会导致和原有切片的分离 。在下例中
由于a的长度超出go语言扩容了容量 , 所以切片a指向了一个增长后的新数组,而b仍然指向原来的老数组 。所以之后对a进行的操作,对b不会产生影响 。
试比较
本例中,a的容量为6 , 因此在append后并未超出容量,所以array指针没有改变 。因此,对a进行的操作,对b同样产生了影响 。
下面看看用a := []int{}这种方式来创建切片会是什么情况 。
可以看到,空切片的容量为0,但后面向切片中添加元素时,并不是每次切片的容量都发生了变化 。这是因为,如果增大容量,也即需要创建新数组,这时还需要将原数组中的所有元素复制到新数组中,开销很大,所以GoLang设计了一套扩容机制,以减少需要创建新数组的次数 。但这导致无法很直接地判断append时是否创建了新数组 。
如果一次添加多个元素,容量又会怎样变化呢?试比较下面两个例子:
那么 , 是不是说 , 当向一个空切片中插入2n-1个元素时,容量就会被设置为2n呢?go语言扩容我们来试试其他的数据类型 。
可以看到,根据切片对应数据类型的不同,容量增长的方式也有很大的区别 。相关的源码包括: src/runtime/msize.go , src/runtime/mksizeclasses.go 等 。
go语言扩容我们再看看切片初始非空的情形 。
可以看到,与刚刚向空切片添加5个int的情况一致,向有3个int的切片中添加2个int,容量增长为6 。
需要注意的是,append对切片扩容时,如果容量超过了一定范围 , 处理策略又会有所不同 。可以看看下面这个例子 。
具体为什么会是这样的变化过程,还需要从 源码 中寻找答案 。下面是src/runtime/slice.go中的growslice函数中的核心部分 。
GoLang中的切片扩容机制,与切片的数据类型、原本切片的容量、所需要的容量都有关系,比较复杂 。对于常见数据类型 , 在元素数量较少时,大致可以认为扩容是按照翻倍进行的 。但具体情况需要具体分析 。
go语言循环队列的实现队列的概念在 顺序队列 中 , 而使用循环队列的目的主要是规避假溢出造成的空间浪费,在使用循环队列处理假溢出时,主要有三种解决方案
本文提供后两种解决方案 。
顺序队和循环队列是一种特殊的线性表,与顺序栈类似 , 都是使用一组地址连续的存储单元依次存放自队头到队尾的数据元素,同时附设队头(front)和队尾(rear)两个指针,但我们要明白一点,这个指针并不是指针变量 , 而是用来表示数组当中元素下标的位置 。
本文使用切片来完成的循环队列,由于一开始使用三个参数的make关键字创建切片,在输出的结果中不包含nil值(看起来很舒服) , 而且在验证的过程中发现使用append()函数时切片内置的cap会发生变化,在消除了种种障碍后得到了一个四不像的循环队列,即设置的指针是顺序队列的指针,但实际上进行的操作是顺序队列的操作 。最后是对make()函数和append()函数的一些使用体验和小结,队列的应用放在链队好了 。
- 将数据保存到文件中c语言 将数据保存到mongodb
- 罗布人村天气 mysql语言具有的功能
- redis编程语言 redis对应c语言
- redis一般和什么语言一起开发 和redis类似的编程
- redishash扩容 redishash容量
- mongodb采用什么语言 mongodb的设计采用什么
- c连接mysql数据库 c连接mysql报错
- mongodb底层数据结构 mongodb底层语言
- mongodb如何批量更新数据 mongodb如何自动扩容
- redis缓存扩容 redis怎么扩展内存
