js素材网站,天坛整装电话,威海做网站优化,网站建设 推广薪资切片
一、切片#xff08;slice#xff09;概念 在讲解切片#xff08;slice#xff09;之前#xff0c;大家思考一下数组有什么问题#xff1f;
数组定义完#xff0c;长度是固定的。例如#xff1a;
var num [5]int [5]int{1,2,3,4,5}定义的num数组长度是5#…切片
一、切片slice概念 在讲解切片slice之前大家思考一下数组有什么问题
数组定义完长度是固定的。例如
var num [5]int [5]int{1,2,3,4,5}定义的num数组长度是5表示只能存储5个整型数字现在向数组num中追加一个数字这时会出错。因为你已经定义死了。
使用数组作为函数参数进行传递时如果实参为5个元素的整型数组那么形参也必须5个元素的整型数组否则出错。
针对以上两个问题可以使用切片来进行解决。
切片与数组的区别 切片与数组相比切片的长度是不固定的可以追加元素在追加时可能使切片的容量增大所以可以将切片理解成“动态数组”但是它不是数组。
二、 切片与数组区别 通过定义来比较一下切片与数组的区别。
先回顾数组的基本定义初始化a : [5]int{}数组中[]是一个固定的数字表示长度。定义完后长度是固定最多存储5个数字。切片的基本定义初始化如下s:[]int{}//定义空切片看定义的方式发现与数组很相似.但是注意切片中的[]是空的或者是“…”。切片的长度和容量可以不固定。现在通过程序演示动态向切片中追加数据
/ 初始化切片
s : []int{1,2,3}
// 通过append函数向切片中追加数据
s append(s,5,6,7)
fmt.Println(s)append()函数第一个参数表示向哪个切片追加数据后面表示具体追加的数据。最终输出结果为 [1 2 3 5 6 7]三、 切片其它定义方式
定义空切片
//声明切片和声明数组一样只是少了长度此为空(nil)切片
var s1 []int 通过make()函数实现
//借助make函数, 格式 make\(切片类型, 长度, 容量\)
s : make([]int, 5, 10)四、切片的长度与容量 长度是已经初始化的空间以上切片s初始空间默认值都是0。容量是已经开辟的空间包括已经初始化的空间和空闲的空间。我们可以通过如下图来理解切片的长度与容量 该切片的长度是5存有数据注意如果没有赋值默认值都是0容量是10只不过有5个空闲区域。即使没有给切片s赋值初始化的空间长度默认存储的数据都是0。 s : make([]int,5,8)
fmt.Println(s)输出的结果是
[0 0 0 0 0]在使用make()函数定义切片时一定要注意切片长度要小于容量例如
// 以下是错误的
s : make([]int, 10, 5)make()函数中的容量参数是可以省略掉的如
s : make([]int,10)这时长度与容量是相等的都是10. GO语言提供了相应的函数来计算切片的长度与容量示例如下
s : make([]int,5,10)
fmt.Println(长度是,len(s))
fmt.Println(容量是,cap(s))接下来给切片s赋值可以通过下标的方式直接来进行赋值。如下所示
s : make([]int,5,10)
s[0] 1
s[1] 2也可以通过循环的方式来进行赋值。
s : make([]int,5,10)
for i:0;ilen(s) ;i {s[i] i
}在这里一定要注意循环结束条件是小于切片的长度而不是容量。因为切片的长度是指的是初始化的空间。以下方式会出现异常错误
for i:0;icap(s) ;i {s[i] i
}给切片赋完值后怎样将切片中的数据打印出来呢
第一种方式直接通过下标的方式输出例如s[0],s[1]…。第二种方式: 通过循环的方式注意循环结束的条件也是小于切片的长度如下所示
for i:0;ilen(s) ;i {fmt.Println(s[i])
}
或者使用range方式输出
for _,v : range s {fmt.Println(v)
}四、 切片截取 首先说一下切片的截取操作所谓截取就是从切片中获取指定的数据。 我们通过如下程序给大家解释一下
//定义切片 并且完成初始化
s : []int{10,20,30,0,0}//从切片s中截取数据
slice : s[0:3:5]
fmt.Println(slice)以上程序输出结果
[10 20 30]其中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计算(lenhigh-low)也就是第二个数减去第一个数差就是数据长度。在这里可以将长度理解成取出的数据的个数。第三个数用来计算容量所谓容量是指切片目前可容纳的最多元素个数。通过公式5-0计算(capmax-low)也就是第三个数据减去第一个数。该案例中容量为5。
现在将以上程序进行修改
//定义切片 并且完成初始化
s : []int{10,20,30,40,50}//从切片s中截取数据
slice : s[0:3:5]
fmt.Println(slice)结果是
[10 20 30]因为起点还是0也就是10开始终点还是3也就是到30结束.长度是3容量是5。
继续修改该程序
//定义切片 并且完成初始化
s : []int{10,20,30,40,50}//从切片s中截取数据
slice : s[0:4:5]
fmt.Println(slice)结果是
[10 20 30 40]因为起点还是0也就是10开始终点还是4也就是到40结束。长度是4容量是5。 继续修改该程序
//定义切片 并且完成初始化
s : []int{10,20,30,40,50}//从切片s中截取数据
slice : s[1:4:5]
fmt.Println(slice)slice切片结果是
[20 30 40]那么容量是多少呢容量为4通过第三个数减去第一个数5-1计算。
通过画图的方式来表示slice切片中的容量。 通过上面的图可以发现切片s经过截取操作以后将结果赋值给切片slice后长度是3容量是4只不过有一块区域是空闲的。
切片其他操作。
如下表所示 下面通过一个案例演示一下。
s[:] 结果是所有的值。
2.s[low:] 结果是下标3后面的所有值。
s[:high] s[low:high] 结果是2-5的值。array[2:5]表示从下标为2的元素包含该元素开始取到下标为5的元素不包含该元素结束。所以切片s5的长度是3。切片s5的容量是多少呢是8根据array切片的容量是10,减去array[2:5]中的2。
以上就是关于切片的基本操作这些操作在以后的开发过程中会经常用到希望大家记住基本的规律。
五、 思考题
接下来说思考如下题定义一个切片array然后对该切片array进行截取操作范围自定义得到新的切片s6,并修改切片s6某个元素的值。代码如下 s6切片的结果是[2,3,4]因为是从下标为2的元素包含开始取到下标为5的元素不包含结束,取出3个元素也就是长度为3。
现在将程序进行如下修改 现在程序的输出结果是
s6 [2 3 888]因为切除了234然后现在0是21是32是4然后把s6[2]也就是s6[4]赋值为888 接下来输出切片array的值 输出的结果如下
s6 [2 3 888]
array [0 1 2 3 888 5 6 7 8 9]发现切片array中的值也发生了变化也就是修改切片s6的值会影响到原切片array的值下面通过画图的形式来说明其原因。 在这里重点要理解的是s6 : array[2:5]将array切片中的array[2]array[3]array[4]截取作为新切片s6实际上是切片s6指向了原切片array在这里并不是为切片s6新建一块区域。所以修改s6也会影响到array。
下面继续修改上面的程序 以上程序中切片s7的值是多少
结果是s7 [888 5 6 7 8]下面也是通过画图的形式来解释该程序的结果 继续思考,现在在原有的程序中又加了一行如下图所示 最终切片s7与原来切片array的值分别是多少
结果所示
s6 [2 3 888]
s7 [888 5 999 7 8]
array [0 1 2 3 888 5 999 7 8 9]六、 append函数的使用
在第一节中已经给大家讲解过切片与数组很大的一个区别就是切片的长度是不固定的可以向已经定义的切片中追加数据。并且也给大家简单的演示过通过append的函数在原切片的末尾添加元素。
arr : []int{1,2,3}
arr append(arr,4) //追加一个数
arr append(arr,5,6,7) //追加多个数
fmt.Println(arr)如果容量不够用了该怎么办呢
例如有以下切片
s: make([]int, 5, 8)定义了切片s长度是5容量是8k。
s : make([]int,5,8)
fmt.Printf(len %d,cap%d\n,len(s),cap(s))结果是len 5 cap 8
并且前面我们讲解过长度是指已经初始化的空间现在切片s没有赋值但是默认值为0 验证如下所示
s : make([]int,5,8)
fmt.Printf(len %d,cap%d\n,len(s),cap(s))
fmt.Println(s)结果是
len 5 cap 8
[0 0 0 0 0]现在开始通过append函数追加数据如下所示:
s : make([]int,5,8)
s append(s,1)
fmt.Println(s)
fmt.Printf(len %d,cap%d\n,len(s),cap(s))输出结果是
[0 0 0 0 0 1]
len 6 cap 8从输出的结果上我们完全能够体会到append函数的作用是在末尾追加直接在默认值后面追加数据由于追加了一个元素所以长度为6.
但是如果我们把程序修改成如下所示
s : make([]int,5,8)
//s append(s,1)
s[0] 1
fmt.Println(s)
fmt.Printf(len %d,cap%d\n,len(s),cap(s))输出结果是
[1 0 0 0 0]
len 5 cap 8由于s[0]1是直接给下标为0的元素赋值并不是追加所以结果的长度不变。
下面我们继续通过append( )继续追加数据
s : make([]int,5,8)
s append(s,1)
s append(s,2)
s append(s,3)fmt.Println(s)
fmt.Printf(len %d,cap%d\n,len(s),cap(s))结果是
[0 0 0 0 0 1 2 3]
len 8 cap 8追加完成3个数据后长度变为了8与容量相同。
那么如果现在通过append( )函数继续向切片s中继续追加一个数据那么容量会变为多少呢
代码如下
s : make([]int,5,8)
s append(s,1)
s append(s,2)
s append(s,3)
s append(s,4)
fmt.Println(s)
fmt.Printf(len %d,cap%d\n,len(s),cap(s))输出的结果是
[0 0 0 0 0 1 2 3 4]
len 9 cap 16追加完成一个数据后长度变为9大于创建切片s时的容量所以切片s扩容变为16.
那么切片的容量是否是以2倍容量来进行扩容的呢
我们可以来验证一下 输出结果是 通过以上结果分析发现是2倍的容量进行扩容。
但是我们修改一下循环条件看一下结果将循环结束的条件修改的大一些如下所示 对应的结果 通过以上的运行结果分析当容量小于1024时是按照2倍容量扩容当大于等于1024就不是按照2倍容量扩容。
七、 copy函数使用
针对切片操作常用的方法除了append()方法以外还有copy方法。
基本语法copy(切片1切片2)
将第二个切片里面的元素拷贝到第一个切片中。
下面通过一个案例看一下该方法的使用 上面案例中将srcSlice中的元素拷贝到destSlice切片中。结果如下
dst [1 2 6 6 6]通过以上结果可以分析出直接将srcSlice切片中两个元素拷贝到dstSlice元素中相同的位置。而dstSlice原有的元素备替换掉。
下面将以上程序修改一下如下所示 以上程序的结果是
src [6 6]通过以上两个程序得出如下结论在进行拷贝时,拷贝的长度为两个slice中长度较小的长度值。
思考以下程序输出的结果 结果是
slice2 [1 2 3]现在将程序进行如下修改 结果是
slice1 [5 4 3 4 5]八、切片作为函数参数
切片也可以作为函数参数那么与数组作为函数参数有什么区别呢
接下来通过一个案例演示一下切片作为函数参数。 通过以上案例发现在主函数main()中定义了一个切片s然后调用InitData()函数将切片s作为实参传递到该函数中并在InitData()函数中完成初始化该函数并没有返回值但是在主函数中直接打印切片s发现能够输出对应的值。也就是在InitData()函数中对形参切片num赋值影响到了main()函数中的切片s。
但是大家仔细想一下如果我们这里传递参数不是切片而是数组那么能否完成该操作呢
那么我们将上面的程序修改成以数组作为参数进行传递的形式 发现以数组的形式作为参数并不能完成我们的要求所以切片作为函数实参与数组作为函数实参进行传递时传递的方式是不一样的。
在GO语言中数组作为参数进行传递是值传递而切片作为参数进行传递是引用传递。
九、值传递和引用传递
值传递方法调用时实参数把它的值传递给对应的形式参数方法执行中形式参数值的改变不影响实际参数的值引用传递也称为传地址。函数调用时实际参数的引用(地址而不是参数的值)被传递给函数中相对应的形式参数实参与形参指向了同一块存储区域在函数执行中对形式参数的操作实际上就是对实际参数的操作方法执行中形式参数值的改变将会影响实际参数的值。
建议以后开发中使用切片来代替数组。