Slice使用的正确姿势
slice是Go中的一个常用的数据结构,日常使用时类似Java中的List。但是这里包含的语言特性又与Java有很大区别。下面介绍一下我使用过程中感觉需要注意的一些问题。
slice的cap与len
在slice创建的时候,我们会指定两个参数len和cap
1 | s := make([]int, 0, 10) |
其中的len是指当前数组容纳的数据数量,cap是指整个数组分配的空间。
看一个例子来理解一下len的使用
1 | s := make([]int, 5, 10) |
这里我们append了四次,但是却输出了九个数,为什么呢?因为我们在初始化的时候,通过默认值将s的前五个数值填充了,后续的append过程中就是在原来的基础上继续添加。
理解完了len,我们再来看看cap。从字面意思看,就是slice容量的意思,这个值可以在创建slice的时候不显示的赋予,这个时候他会和len保持一致。那么如果在给定了cap大小的slice上继续添加数据会发生什么呢?
1 | type StA struct{ |
这里按照以前的编程经验,应该会返回data2,但是结果返回的是data1。原因是当slice所需的长度,超过了他自身的容量时,slice会自动进行扩容,产生新的slice,然后将原slice中的数据copy到新的slice中。所以扩容后的s中存储的是data1的副本,修改data1已经对s产生不了任何影响了。
这里需要注意一点,虽然slice进行了copy,创建了新的slice2,然后将slice2 赋值给原来的slice。但是slice的指针地址并没有变。
1 | s0 := make([]int, 0) |
这是因为go中的赋值,发生了数据拷贝,而不是简单的指针指向的修改。关于这个问题,我们后续会单独进行一次分析。