GoLang中的切片扩容机制[5]int是数组,而[]int是切片 。二者看起来相似,实则是根本上不同的数据结构 。
切片的数据结构中 , 包含一个指向数组的指针array,当前长度len,以及最大容量cap。在使用make([]int, len)创建切片时,实际上还有第三个可选参数cap,也即make([]int, len, cap)。在不声明cap的情况下,默认cap=len。当切片长度没有超过容量时,对切片新增数据,不会改变array指针的值 。
当对切片进行append操作,导致长度超出容量时,就会创建新的数组 , 这会导致和原有切片的分离 。在下例中
由于a的长度超出了容量,所以切片a指向了一个增长后的新数组,而b仍然指向原来的老数组 。所以之后对a进行的操作,对b不会产生影响 。
试比较
本例中,a的容量为6,因此在append后并未超出容量,所以array指针没有改变 。因此,对a进行的操作 , 对b同样产生了影响 。
下面看看用a := []int{}这种方式来创建切片会是什么情况 。
可以看到,空切片的容量为0,但后面向切片中添加元素时,并不是每次切片的容量都发生了变化 。这是因为,如果增大容量,也即需要创建新数组,这时还需要将原数组中的所有元素复制到新数组中 , 开销很大 , 所以GoLang设计了一套扩容机制,以减少需要创建新数组的次数 。但这导致无法很直接地判断append时是否创建了新数组 。
如果一次添加多个元素 , 容量又会怎样变化呢?试比较下面两个例子:
那么,是不是说 , 当向一个空切片中插入2n-1个元素时 , 容量就会被设置为2n呢?我们来试试其他的数据类型 。
可以看到 , 根据切片对应数据类型的不同 , 容量增长的方式也有很大的区别 。相关的源码包括: src/runtime/msize.go , src/runtime/mksizeclasses.go 等 。
我们再看看切片初始非空的情形 。
可以看到,与刚刚向空切片添加5个int的情况一致,向有3个int的切片中添加2个int,容量增长为6 。
需要注意的是,append对切片扩容时,如果容量超过了一定范围,处理策略又会有所不同 。可以看看下面这个例子 。
具体为什么会是这样的变化过程,还需要从 源码 中寻找答案 。下面是src/runtime/slice.go中的growslice函数中的核心部分 。
GoLang中的切片扩容机制,与切片的数据类型、原本切片的容量、所需要的容量都有关系,比较复杂 。对于常见数据类型 , 在元素数量较少时,大致可以认为扩容是按照翻倍进行的 。但具体情况需要具体分析 。
slice切片做函数参数再来分析一下golang中的切片slice底层的实现细节 。
slice通过数组实现go语言中切片如何作参数,类似一个结构体go语言中切片如何作参数,其中一个字段保存的是底层数组的地址 , 还有长度(len) 和 容量(cap)两个字段 。
我们都知道,结构体作为函数参数时是值拷贝,同理,实际上slice作为函数参数时也是值拷贝,在函数中对slice的修改是通过slice中保存的地址对底层数组进行修改,所以函数外的silce看起来被改变了 。
当需要对slice做插入和删除时(如go语言中切片如何作参数:append操作) , 由于需要更改slice结构体中的长度字段,值拷贝就行不通了,需要传slice本身在内存中的地址 。
看一个值传递的例子go语言中切片如何作参数:
```
package main
import "fmt"
func processSlice(x []int) {
x = append(x, 6)
}
func main() {
var numbers = []int{1, 2, 3, 4, 5}
processSlice(numbers)
推荐阅读
- jquery中文版,jquery 中文
- 下载迷你.,下载迷你世界恐龙版本
- 区块链技术趋势存储,区块链存储的技术
- 浩方cs服务器,浩方平台cs设置路径不对
- python反函数精度 python怎么求反三角函数
- 怎么把电脑u盘启动,如何使电脑u盘启动
- unity3.0游戏开发,unity游戏开发技术详解与典型案例
- 关于经营军舰游戏,关于经营军舰游戏的电影
- linux写入网口命令 linux给网口配地址