DataWhale & Golang(六、数组、切片)
学习大纲:
目录
补充:
数组:
- 数组是一种非常有用的数据结构,因为其占用的内存是连续分配的。
- 由于内存连续,CPU能把正在使用的数据缓存更久的时间。
- 而且内存连续很容易计算索引,可以快速迭代数组里的所有元素。
- 数组的类型信息可以提供每次访问一个元素时需要在内存中移动的距离。
- 既然数组的每个元素类型相同,又是连续分配,就可以以固定速度索引数组中的任意数据,提高工作效率。
- 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。
- 相对于去声明 number0, number1, ..., number99 的变量,使用数组形式 numbers[0], numbers[1] ..., numbers[99] 更加方便且易于扩展。
- 数组元素可以通过索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1,以此类推。
数组声明和初始化:
- Go 语言数组声明需要指定元素类型及元素个数
var variable_name [SIZE] variable_type
- golang中声明数组需要告诉数组长度,以及存放数据类型,一旦初始化成功,那么存储的数据类型和数组长度就都不能改变了
- 初始化数组中 {} 中的元素个数不能大于 [] 中的数字。
- 如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小
- 如果需要存储更多的元素,就需要先创建一个更长的数组,再把原来数组里的值复制到新数组里
- 数组元素可以通过索引(位置)来读取(或者修改),索引从0开始,第一个元素索引为 0,第二个索引为 1,以此类推。
二维数组
二维数组是最简单的多维数组,二维数组本质上是由一维数组组成的。二维数组定义方式如下:
var arrayName [ x ][ y ] variable_type
variable_type 为 Go 语言的数据类型,arrayName 为数组名,二维数组可认为是一个表格,x 为行,y 为列,下图演示了一个二维数组 a 为三行四列:
- 二维数组中的元素可通过 a[ i ][ j ] 来访问。
访问二维数组
二维数组通过指定坐标来访问。如数组中的行索引与列索引,例如:
- val := a[2][3] 或 var value int = a[2][3]
len() 和 cap() 函数
- 切片是可索引的,并且可以由 len() 方法获取长度。
- 切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。
6.1 数组
6.1.1 如何定义数组
数组是具有相同类型且长度固定的一组连续数据。以下方式定义数组,
//方式一
var arr1 = [5]int{}
//方式二
var arr2 = [5]int{1,2,3,4,5}
//方式三
var arr3 = [5]int{3:10}
输出以上三个变量的值如下所示:其中[3]int与[4]int是两种不同的数据类型
arr1 [0 0 0 0 0]
arr2 [1 2 3 4 5]
arr3 [0 0 0 10 0]
- - 方法一在声明时没有为其指定初值,所以数组内的值被初始化为类型的零值。
- - 方法二使用显示的方式为数组定义初值。
- - 方法三通过下标的方式为下标为3的位置赋上了初值10
6.1.1 如何操作数据
- 可以通过循环的方式为其赋予初值
- 可以通过循环的方式遍历数组,for循环提供这样的方式来为便利数组
- 通过range来遍历数组会有两个返回值,其中第一个为数组的索引,第二个位置为对应的值
- 当然不想要索引值也是可以的,可以用`_`代替。
6.1.3 多维数组
与其他语言一样,go语言也可以定义多维数组,可以选择的定义方式如下:
var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type以下实例声明了三维的整型数组:
var threedim [5][10][4]int
#多维数组
var arr4 = [5][5]int{
{1, 2, 3, 4, 5},
{6, 7, 8, 9, 10},
}
arr4
[[1 2 3 4 5] [6 7 8 9 10] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
6.1.4 数组作为函数参数
go语言在传递数组时会对其进行拷贝,所以如果传递的是大数组的话会非常占内存,所以一般情况下很少直接传递一个数组,避免这种情况我们可以使用以下两种方式:
- - 传递数组的指针
- - 传递切片
6.1.5 指针数组与数组指针
对于指针数组和数组指针在c或c++中也经常被讨论,尤其对于初学者来说会分辨不清楚。其实在每个词中间添加一个“的“就很好理解了,指针的数组,数组的指针。
a、指针数组
- 对于指针数组来说,就是:一个数组里面装的都是指针,在go语言中数组默认是值传递的,所以如果我们在函数中修改传递过来的数组对原来的数组是没有影响的。
- 但是如果我们一个函数传递的是指针数组,初始化值全是nil,也就验证了指针数组内部全都是一个一个指针,之后我们将其初始化,内部的每个指针指向一块内存空间。
注意:
- 在初始化的时候如果直接另a[i] = &i那么指针数组内部存储的全是同一个地址,所以输出结果也一定是相同的*
b、数组指针
- 我们都知道,变量是一种使用方便的占位符,用于引用计算机内存地址。
- Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。
6.2.切片
- 因为数组是固定长度的,所以在一些场合下就显得不够灵活,所以go语言提供了一种更为便捷的数据类型叫做切片。
- 切片操作与数组类似,但是它的长度是不固定的。
- 可以追加元素,如果以达到当前切片容量的上限会再自动扩容。
6.2.1 如何定义切片
可以通过以下几种方式定义切片
//方法一
var s1 = []int{}
//方法二
var s2 = []int{1, 2, 3}
//方法三
var s3 = make([]int, 5)
//方法四
var s4 = make([]int, 5, 10)
- 方法一声明了一个空切片
- 方法二声明了一个长度为3的切片
- 方法三声明了一个长度为5的空切片
- 方法四声明了一个长度为5容量为10的切片。
- 可以看到切片的定义与数组类似,但是定义切片不需要为其指定长度。
6.2.2 切片初始化
s :=[] int {1,2,3 }
直接初始化切片,[]表示是切片类型,{1,2,3}初始化值依次是1,2,3.其cap=len=3
s := arr[:]
初始化切片s,是数组arr的引用
s := arr[startIndex:endIndex]
将arr中从下标startIndex到endIndex-1 下的元素创建为一个新的切片
s := arr[startIndex:]
默认 endIndex 时将表示一直到arr的最后一个元素
s := arr[:endIndex]
默认 startIndex 时将表示从arr的第一个元素开始
s1 := s[startIndex:endIndex]
通过切片s初始化切片s1
s :=make([]int,len,cap)
通过内置函数make()初始化切片s,[]int 标识为其元素类型为int的切片
6.2.3 切片的扩充与拼接
append() 和 copy() 函数
如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。
下面的代码描述了从拷贝切片的 copy 方法和向切片追加新元素的 append 方法。
package main
import "fmt"
func main() {
var numbers []int
printSlice(numbers)
/* 允许追加空切片 */
numbers = append(numbers, 0)
printSlice(numbers)
/* 向切片添加一个元素 */
numbers = append(numbers, 1)
printSlice(numbers)
/* 同时添加多个元素 */
numbers = append(numbers, 2,3,4)
printSlice(numbers)
/* 创建切片 numbers1 是之前切片的两倍容量*/
numbers1 := make([]int, len(numbers), (cap(numbers))*2)
/* 拷贝 numbers 的内容到 numbers1 */
copy(numbers1,numbers)
printSlice(numbers1)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
运行结果:
len=0 cap=0 slice=[]
len=1 cap=1 slice=[0]
len=2 cap=2 slice=[0 1]
len=5 cap=6 slice=[0 1 2 3 4]
len=5 cap=12 slice=[0 1 2 3 4]