(2.1)切片(slice)概念

在讲解切片(slice)之前,大家思考一下数组有什么问题?
第一:数组定义完,长度是固定的。
例如:
4.png
定义的num数组长度是5,表示只能存储5个整型数字,现在向数组num中追加一个数字,这时会出错。
第二:使用数组作为函数参数进行传递时,如果实参为5个元素的整型数组,那么形参也必须5个元素的整型数组,否则出错。
针对以上两个问题,可以使用切片来进行解决。
切片:切片与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大,所以可以将切片理解成“动态数组”,但是,它不是数组。

(2.2)切片与数组区别

通过定义,来比较一下切片与数组的区别
(1)先回顾数组的基本定义初始化:
a:=[5]int{ }
数组中[ ]是一个固定的数字,表示长度。定义完后,长度是固定,最多存储5个数字。
(2)切片的基本定义初始化如下:
s:=[ ]int{ }//定义空切片
看定义的方式,发现与数组很相似,但是注意:切片中的[ ]是空的,或者是“…”.切片的长度和容量可以不固定。
现在通过程序演示,动态向切片中追加数据
5.png
append( )函数,第一个参数表示向哪个切片追加数据,后面表示具体追加的数据。
最终输出结果为:
6.png

(2.3)切片其它定义方式

(3)切片第二种定义方式:
var s1 []int //声明切片和声明数组一样,只是少了长度,此为空(nil)切片
(4)切片第三中定义方式,通过make( )函数实现
// 借助make函数, 格式 make(切片类型, 长度, 容量)
s := make([]int, 5, 10)
什么是切片的长度与容量?
长度是已经初始化的空间(以上切片s初始空间默认值都是0)。容量是已经开辟的空间,包括已经初始化的空间和空闲的空间。
我们可以通过如下图来理解切片的长度与容量:
7.png
该切片的长度是5(存有数据,注意如果没有赋值,默认值都是0),容量是10,只不过有5个空闲区域。
即使没有给切片s赋值,初始化的空间(长度)默认存储的数据都是0。
演示如下:
8.png
输出的结果是:
9.png
在使用make( )函数定义切片时,一定要注意,切片长度要小于容量,例如:
s := make([]int, 10, 5)是错误的。
make( )函数中的容量参数是可以省略掉的,如:
10.png
这时长度与容量是相等的,都是10.
GO语言提供了相应的函数来计算切片的长度与容量。
11.png
接下来给切片s赋值,可以通过下标的方式直接来进行赋值。如下所示:
12.png
也可以通过循环的方式来进行赋值。
13.png
在这里一定要注意,循环结束条件是小于切片的长度,而不是容量。因为,切片的长度是指的是初始化的空间。以下方式会出现异常错误。
14.png
给切片赋完值后,怎样将切片中的数据打印出来呢?
第一种方式:直接通过下标的方式输出,例如:s[0],s[1]…..。
第二种方式:通过循环的方式,注意循环结束的条件,也是小于切片的长度,如下所示:
15.png
或者使用range方式输出:
16.png

(2.4)切片截取

上一小节中,已经完成了切片的定义,赋值等操作,接下来看一下关于切片的其它操作。首先说一下切片的截取操作,所谓截取就是从切片中获取指定的数据。
我们通过如下程序给大家解释一下:
17.png
以上程序输出结果:
18.png
s[0:3:5]是什么意思呢?
我们可以使用s[low:high:max]来表示
第一个数(low)表示下标的起点(从该位置开始截取),如果low取值为0表示从第一个元素开始截取,也就是对应的切片s中的10
第二个数(high)表示取到哪结束,也就是下标的终点(不包含该位置),3表示取出下标是0,1,2的数据(10,20,30),不包括下标为3的数据,那么也就是说取出的数据长度是3. 可以根据公式:3-0 计算(len=high-low),也就是第二个数减去第一个数,差就是数据长度。在这里可以将长度理解成取出的数据的个数。
第三个数用来计算容量,所谓容量:是指切片目前可容纳的最多元素个数。通过公式5-0计算(cap=max-low),也就是第三个数据减去第一个数。该案例中容量为5
现在将以上程序进行修改:
19.png
结果是:
20.png
因为起点还是0,终点还是3.长度是3,容量是5。
继续修改该程序:
21.png
结果是:
22.png
继续修改该程序
23.png
slice切片结果是:
24.png
那么容量是多少呢?容量为4,通过第三个数减去第一个数(5-1)计算。
通过画图的方式来表示slice切片中的容量。
25.png
通过上面的图,可以发现切片s经过截取操作以后,将结果赋值给切片slice后,长度是3,容量是4,只不过有一块区域是空闲的。
关于切片的截取还有其它的操作,如下图所示:

** **
s[n] 切片s中索引位置为n的项
s[:] 从切片s的索引位置0到len(s)-1处所获得的切片
s[low:] 从切片s的索引位置low到len(s)-1处所获得的切片
s[:high] 从切片s的索引位置0到high处所获得的切片,len=high
s[low:high] 从切片s的索引位置low到high处所获得的切片,len=high-low
s[low:high:max] 从切片s的索引位置low到high处所获得的切片,len=high-low,cap=max-low
len(s) 切片s的长度,总是<=cap(s)
cap(s) 切片s的容量,总是>=len(s)

下面通过一个案例,演示一下:
(1)s[:]
26.png
(2)s[low:]
27.png
(3)s[:high]
28.png
(4)s[low:high]
29.png
array[2:5] 表示从下标为2的元素(包含该元素)开始取,到下标为5的元素(不包含该元素)结束。所以切片s5的长度是3。切片s5的容量是多少呢?是8,根据array切片的容量是10, 减去array[2:5]中的2。
以上就是关于切片的基本操作,这些操作在以后的开发过程中会经常用到,希望大家记住基本的规律。

(2.5)思考题

接下来说,思考如下题,定义一个切片array,然后对该切片array进行截取操作(范围自定义),得到新的切片s6, 并修改切片s6某个元素的值。代码如下:
30.png
s6切片的结果是:[2,3,4] 因为是从下标为2的元素(包含)开始取,到下标为5的元素(不包含)结束,取出3个元素,也就是长度为3。
现在将程序进行如下修改:
31.png
现在程序的输出结果是:
32.png
接下来输出切片array的值:
33.png
输出的结果如下: