博客 记录生活,记录工作。

golang基础-07-slice的截取和追加

2019-04-28
gongmh
go

熟悉slice底层实现的同学都知道,slice底层结构实包含的是指针、长度和容量,指针指向底层的数据数组。当我们对切片进行截取或追加时,如果不注意截取和追加的基本规则,可能会有意想不到的结果。下面先通过两个例子来看看问题,然后我们再具体分析。

例1 (运行)

	s := []int{1, 2, 3, 4, 5}
	a := s[2:3]  // diff

	a = append(a, 1)

	fmt.Println(s, a)

例2 (运行)

	s := []int{1, 2, 3, 4, 5}
	a := s[2:3:3]  //diff

	a = append(a, 1)

	fmt.Println(s, a)

这两个例子输出是什么呢? 会一样吗? 我们可以先思考下,尝试自己执行看看和理解的是否一致。

在看答案前,我们先巩固下slice截取和追加的一些基本原则。

首先slice的截取,slice一般的截取格式是 a := s[low:high:max],主要包含以下几点:

1)low表示截取开始的index,包含该index;
2)high表示截取结束的index,不包含index;
3)max表示截取后的容量的index,不包含index;
4)不设置max则max为被截取slice的cap;

因此截取后的a,起始index为low,len为high-low,cap为max-low。

而追加的规则就比较简单了,slice追加 a = append(a, ele),主要有两个原则:

1)slice有剩余空间即cap-len>0,在原slice上追加;
2)slice无剩余空间,则重新分配底层数组空间,扩容copy后,再进行追加;

有了上面的基本原则,我们就能分析出来上面的结果了。

在例1中,a的起始index为2,len为3-2=1,cap则为5-2=3。因此append时,a中还有容量,在原slice上追加,此时也会改变s的内容。因此输出为:

//example 1 output
[1 2 3 1 5] [3 1]  

而例2,a的起始index同样为2,len也为3-2=1,但是cap为3-2=1。因此append时,a中没有容量,需要在重新分配底层数据空间,再追加。因此输出为:

//example 2 output
[1 2 3 4 5] [3 1]  

因此,由于存在多个slice指向同一个底层数据数组的情况,append的时候就需要根据当前slice的cap决定是否影响底层数据数组的内容。

对于slice了解较少的,可以复习下go官网的blog slices-intro。同时,也可以参考前面文章golang基础-01-array、slice和map分析下slice截取追加前后底层指针及容量的变化情况。


相关博文

评论