当前位置: 首页 > 科技观察

Go语言为你带来的数组和切片

时间:2023-03-16 01:14:20 科技观察

数组数组是一组类型相同、长度固定、按编号排列的数据序列。由于在go语言中,数组具有相同的类型和固定的长度,所以这两个特性在声明数组的时候就会体现出来。vararray[5]int//[00000]数组的声明形式为[SIZE](方括号中数组的长度)加上TYPE(类型),上面代码表示数组变量是长度为5,5个数据为int类型。之前介绍变量的时候介绍过int类型的默认值为0,所以array的值为[00000]。数组初始化在数组的初始化阶段,需要通过{}指定数组各个位置的具体值。vararray[3]int=[3]int{1,2,3}//[123]可以看到{}前面还要加上数组的长度和类型。由于go可以进行类型推导,所以变量类型后面的声明有点多余,可以省略。vararray=[3]int{1,2,3}//[123]🎶在指定索引赋值初始化的过程中,我们也可以指定索引进行赋值,即不需要为数组的每个位置都安排具体的值。vararray=[5]int{1:77,3:77}//[0770770]上面数组输出的结果是:[0770770]。和其他语言一样,数组的索引从0开始,我们给索引1和位置3都赋值77,由于其他位置没有指定具体值,所以是其类型的默认值。🎶数组长度的自动推导前面的案例都是指定了数组的长度。事实上,我们可以通过[...]的方式告诉go编译器数组的长度尚未确定,Go会在编译阶段自动推导它。vararray=[...]int{1,2,3,4,5}//[12345]fmt.Println("arraylengththis",len(array))我们可以通过len方法得到数组的长度,上面代码运行结果如下:如果我们在指定索引的位置赋值,最后的长度取决于最后一个索引。在下面的代码中,指定索引5的值为77,数组的长度为6。vararray=[...]int{1:77,5:77}//[07700077]fmt.Println("arraylengththis",len(array))赋值和访问与其他语言相同,数组由[Index]操作。vararray=[...]int{1,2,3}array[0]=100//索引0的位置重新赋值给100fmt.Println("arrayis",array)也是同样的操作,我们现在实现A求数组平均值的函数:funcgetAverage(array[5]int)float32{varsumintvaravgfloat32fori:=0;i<5;i++{sum+=array[i]}avg=float32(sum)/5returnavg}vararray=[5]int{1,2,3,4,5}fmt.Println("averageis",getAverage(array))多维数组的声明,相对于一维数组,就是看有多少[SIZE]在前面。vara1[2][3]int//二维数组vara1[2][3][4]int//三维数组我们以三维数组为例,第一个[]中的数字表示最外层数组的长度,等等。[2][3][4]int表示最外层数组长度为2,第二个数组长度为3,最内层数组长度为4,其赋值方法同a维数组,只不过多维数组需要嵌套多个{}。vara1=[2][3][4]int{{{1,2,3,4},{1,2,3,4},{1,2,3,4},},{{1,2,3,4},{1,2,3,4},{1,2,3,4},},}fmt.Println(a1)打印结果:访问多维数组同一个维数组,也是通过[]+数组索引,只不过多维数组需要多个[]来访问一个值。如果我们要得到下图中的2,访问方式为:array[0][1][1]fmt.Println("array[0][1][1]=",array[0][1][1])切片前面说过,数组是一组相同类型且长度固定的数据集合,而切片是相对抽象的数组,其长度不固定,声明方式与数组(数组不显示在[]length,也不要用[...]推算长度):varslice[]intsliceinitializationslice的初始化类似于数组,只要长度[]中标记的数组的省略:vars1=[]int{1,2,3}s2:=[]int{1,2,3}//简写除了这种字面量声明方式外,还可以初始化通过go的内置方法切片:make:vars1=make([]int,3)s2:=make([]int,3)//缩写make方法的第二个参数表示切片的长度。虽然切片的长度是可变的,但是在通过make方法创建切片的时候,需要指定一个长度。make方法除了指定切片的长度外,还支持传入第三个参数,用于指定切片的“容量”。如果不指定切片的容量,则初始状态下切片的容量与长度相同。funcmake([]T,len,cap)的长度和容量是指切片中有多少个元素,容量可以理解为当前切片在内存中开辟了多少空间。上面说了可以通过len方法获取数组的长度,也可以使用该方法获取切片的长度。要获取切片的容量,可以使用cap方法。s1:=make([]int,5)fmt.Printf("Thelengthofs1is%d\n",len(s1))fmt.Printf("Thecapacityofs1is%d\n",cap(s1))可以看到初始状态接下来,切片的长度与容量相同。如果要修改切片的长度,可以使用append方法在切片的末尾追加一个新值。s1:=make([]int,3,5)//声明一个长度为3,容量为5的sections1=append(s1,1)//在末尾追加一个值,长度变为4fmt.Printf("Thelengthofs1is%d\n",len(s1))fmt.Printf("Thecapacityofs1is%d\n",cap(s1))append方法可以接受多个参数,我们添加一个值后继续调用append方法,添加两个值到切片:s1:=make([]int,3,5)s1=append(s1,1)s1=append(s1,2,3)fmt.Println(s1)//[000123]fmt.Printf("Thelengthofs1is%d\n",len(s1))fmt.Printf("Thecapacityofs1is%d\n",cap(s1))此时slice的长度变成了6,超过了容量slice,此时switching的capacity会不会也变成6?根据输出结果,此时slice的容量变成了10,也就是说slice的容量在之前的基础上扩容了一倍。为了验证这个结论,我们继续在slice后面追加5个值,这样slice的长度就变成了11,超过了当前的容量,看看容量会变成多少。s1:=make([]int,3,5)s1=append(s1,1)s1=append(s1,2,3)s1=append(s1,4,5,6,7,8)fmt.Printf("Thelengthofs1is%d\n",len(s1))fmt.Printf("Thecapacityofs1is%d\n",cap(s1))可以看到slice的容量变成了20,也验证了我们之前的结论,当切片长度超过其容量时,容量将在原来的基础上增加一倍。如果分片容量达到2000,长度超过2000,容量会变成4000吗?s1:=make([]int,1024)s1=append(s1,1)fmt.Printf("\nThelengthofs1is%d\n",len(s1))fmt.Printf("Thecapacityofs1is%d\n",cap(s1))可以看出我们新定义的slice的长度是1024,当长度变成1025时,容量并没有翻倍。为了避免切片容量的无休止扩张,go规定如果当前切片的长度大于1024,当长度超过其容量时,容量只会增加25%。SlicingIntercepts切片之所以称为切片,是因为它可以通过切出数组的一部分来创建。语法规则也很简单:Array[start:end]。arr:=[5]int{1,2,3,4,5}slice:=arr[1:3]fmt.Println(slice)//[23]arr[1:3]表示数组的索引将1的位置到索引3(不包括3)的位置截取,组成一个slice。当然,也可以省略开头和结尾的数字。如果我们省略开头,则表示截取的起始位置为0,省略结尾则表示截取的结束位置到达数组的最后一位。arr:=[5]int{1,2,3,4,5}slice:=arr[1:]fmt.Println(slice)//[2345]通过省略截取的开始和结束,我们可以转换a数组被复制一次,然后形成一个切片。(PS.截取操作形成的新数据是一个slice)arr:=[5]int{1,2,3,4,5}slice:=arr[:]fmt.Printf("slice=%v,slicetype是%T",slice,slice)