在go语言的学习中,少不了接触的就是数组和数组切片,并且这两者的使用也是非常频繁的。因此如果不能进行很好的理解,或许很容易犯错。那么在go中,数组和数组切片都有什么特点,又是怎么声明赋值的,如何使用的呢,下面我就自己的理解总结一下,个人总结可能不全或者有错,望指点。
一、数组和数组切片的特点
数组是什么就不用多说了,作为开发者,这是经常会用到的东西,相信大家都有自己的理解。现在先总结一下数组的特点
1. 数组的长度在定义之后就不可被更改
2. 数组声明时的长度必须为常量或常量表达式,即可以在编译器确定长度,分配内存
3. 数组的下标从0开始,最后一个元素的下标为(长度-1),即在go中可以写为 len(arr)-1
4. go语言的数组是值类型,在作为参数传递时会做数组的复制操作。因此作为参数传递的时候,被修改的内容不影响原来的数组内容,只影响传入函数内的副本
数组切片:是go提供的一种新型的数据类型,它在go语言中的使用有C或C++中的指针的功效。但由于它又不同于指针,所以没有C或C++中语言的指针操作方式。数组切片的底层是通过数组实现,很容易联想到C++的vector。
1. 与数组不同,数组切片的长度是可变的,即可以动态分配内存空间。但在每次新分配空间的时候,即会对当前的元素进行一次复制
2. go语言提供了内置函数copy用于将内容从一个数组切片复制到另外一个数组切片,但如果两个数组切片的长度不一样,则会按照较小的数组切片的个数进行复制。
3. 数组切片与数组一样,其下标从0开始,最后一个元素的下标为(长度-1),即在go中可以写为 len(arr)-1
4. go语言提供cap()内置函数可以获得数组切片分配的空间大小,该值的返回可能与len()返回的大小不同
5. 数组切片提供创建时指定长度和预留存储空间。在知道数组切片最终能用到的长度时,可以避免切片扩容所引发的内存的申请释放与复制。
6. 数组切片作为参数传递时,不会出现内存的复制操作,在函数中如果修改了传入的切片的参数,可以直接修改原数组切片的内容。
二、数组与数组切片的使用
(一) 声明与创建
数组的定义初始化比较简单,如下:
1. var arr [10]int //声明长度为10,类型为int的数组。也可以声明多维数组,如:var twod [10][100]int。也可以定义复杂类型数组,如:var st_arr [100]struct {x, y int }
arr[1] = 1 //根据索引赋值
2. arr := [5]int{1,2,3,4,5} //声明并初始化数组
3. var arr [5]int = [5]int{1,2,3,4,5} //定义并初始化数组
数组切片的定义与初始化,如下:
1. 基于数组创建
arr := [10]int{1,2,3,4,5}
var slc1 []int = arr[:] //基于数组全部元素创建切片
var slc2 []int = arr[:5] //基于前五个元素创建切片
var slc3 []int = arr[5:] //基于从第五个元素创建切片
var slc4 []int = arr[2:8] //基于从第二个到第八个元素创建切片
以上几种创建切片的方式,都是基于一种创建规则:基于arr[first:last]这种方式创建数组切片
2. 直接创建
slice1 := make([]int, 5) //创建一个初始元素个数为5的数组切片,元素初始值为0
slice2 := make([]int, 5, 10) //创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间
slice3 := []int{1, 2, 3, 4, 5} //直接创建并初始化包含5个元素的数组切片
3. 基于数组切片创建数组切片
基于数组切片创建数组切片和基于数组创建切片基本相同。但新创建的切片元素个数可以超过旧切片所包含的元素个数,该操作要求新创建切片的元素个数不超过旧切片的容量个数。如:
slice1 := make([]int, 5, 10)
slice2 := slice1[:6]
(二)遍历元素
在go中,无论是数组还是数组切片,都提供了两种相同的遍历方式:
1. 使用传统的for遍历:
for i := 0; i < len(arr); i++ {
fmt.Println("arr[",i,"] is ", arr[i])
}
2. 使用range关键字:
for i, v := range arr {
fmt.Println("arr[",i,"] is ", v)
}
(三) 长度获取
对于数组和数组切片,go语言提供了内置函数len(),使用方式len(arr),返回当前数组或数组切片的长度。对于数组切片,go语言提供内置函数cap()获取数组切片的容量
(四)添加元素
对于数组定长,因此没有添加元素的功能。但数组切片因为动态内存的问题,可以提供追加元素。在go语言中提供了内置函数append作为数组切片的元素追加。有以下两种使用方式:
1. 直接追加元素:
slice1 := []int{1,2,3,4}
slice1 = append(slice1, 5, 6, 7) // append的第一个参数是基于的数组切片。第二个参数是不定参数,可以追加多个元素
2. 数组切片追加数组切片:
slice1 := []int{1,2,3,4}
slice2 := []int{5,6,7,8}
slice1 := append(slice1, slice2…) //这里要特别注意的是:在第二个数组切片后面需要加三个点,否则会编译错误。主要原因是append第二个参数起都是待追加的元素,而加上三个点的作用就是把slice2的元素按照元素内容列表传入,而不是以切片作为参数传入。
(五)作为参数传递
1. 数组作为参数
func sort(arr [10] int) {
...
}
该函数的调用要如下:
arr1 := [10]int{8,6,5,4,7,3,9,1,2,10}
arr2 := [5]int{4,2,3,5,1}
slice1 := []int{8,6,5,4,7,3,9,1,2,10}
sort(arr) //编译正常,但由于数组穿参属于值传参,在传参的时候会进行数组复制,因此只修改了sort内部的arr的值,未修改arr1的实际元素值内容
sort(arr2) //编译错误,对于go而言,[10]int 和[5]int 是两种不同的数据类型
sort(&arr) //编译错误,对于C或C++而言,函数参数定义为int arr[10]这种实际是定义了数组的指针传入。但go语言中,数组指针和数组是两种完全不同的类型
sort(slice1) //编译错误,同样是因为类型不同
2. 数组切片作为参数
func sort(arr []int) {
...
}
arr1 := [10]int{8,6,5,4,7,3,9,1,2,10}
slice1 := []int{8,6,5,4,7,3,9,1,2,10}
sort(arr) //编译错误,类型不同
sort(slice1) //编译正确,且在sort中对于slice的修改会直接修改到原始的slice。
有疑问加站长微信联系(非本文作者)