数组和切片
数组
- Go中数组是一个长度固定的数据类型,用于存储一段具有相同的类型的元素的连续块。
- 由于元素类型相同,又是连续分配,是一种高效的数据结构
- 声明&初始化
go // 声明一个包含 5 个元素的整型数组,此时该数组元素为对应的零值 var array [5]int
go // 字面量声明初始化 // 声明一个包含 5 个元素的整型数组 // 用具体值初始化每个元素 array := [5]int{10, 20, 30, 40, 50}
// 声明一个整型数组
// 用具体值初始化每个元素
// 容量由初始化值的数量决定
array := [...]int{10, 20, 30, 40, 50}
// 声明一个有 5 个元素的数组
// 用具体值初始化索引为 1 和 2 的元素
// 其余元素保持零值
array := [5]int{1: 10, 2: 20}
数组赋值给另一个数组时,必须确保长度和元素类型都相同才可行
多维数组可以按维度赋值
Go的数组和C相同,索引从0开始
给指针数组赋值时,需注意元素是否已经分配内存,若没分配会引发panic
// 声明一个有 5 个元素的指针数组,1,3两个元素分配了内存,其他均为nil
array := [5]*int{1:new(int),3:new(int)}
// 若要对0元素赋值,需先分配内存
array[0] = new(int)
*array[0] = 1
// 下标为1的元素可以直接赋值
*array[1] = 2
- 函数之间直接传递数组为值拷贝,函数体内对该数组的修改不会影响原始数组
- 函数之间传递数组的指针,也是值传递,只不过这个值是指向该数组的地址,所以函数体内对该数组的修改会影响原始数组
区分指针数组和数组的指针
//指针数组,元素为指针 var array [5]*int //数组的指针,是一个地址,指向数组的指针 func f(a *[5]int)
切片
切片可以理解为动态的数组,其底层为数组
切片的三要素:指向底层数组的指针,长度,容量,容量>=长度
声明&初始化
//创建一个字符串切片
//其长度和容量都是5
slice := make([]string, 5)
//创建一个整型切片
//其长度为3,容量为5
slice := make([]int, 3, 5)
//字面量定义切片
slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"}
slice := []int{10, 20, 30}
//创建字符串切片
//使用空字符串初始化第100个元素
slice := []string{99: ""}
- nil和空切片
//创建 nil 整型切片
//三要素:指针为nil,长度和容量均为0
var slice []int
// 使用 make 创建空的整型切片
slice := make([]int, 0)
// 使用切片字面量创建空的整型切片
slice := []int{}
//三要素:指针不为空,长度和容量均为0,但是底层数组包含0个元素,实际也未分配内存
- 赋值
//原始切片,长度为5,容量为5
slice := []int{1,2,3,4,5}
//包含两个元素2,3,长度为2,容量为4
newSlice := slice[1:3]
//通用公式,slice容量为k
//newSlice容量为k-i
//newSlice长度为j-i
newSlice := slice[i:j]
//还有一种用来控制新切片的容量,范围[i,j),容量k-i,k小于原始容量
newSlice := slice[i:j:k]
- 修改切片,由于实际修改的是底层数组,所以对所有引用该底层数组的切片都有影响
slice := []int{1,2,3,4,5}
newSlice := slice[1:3]
newSlice[1] = 9
//newSlice的元素为,2,9
//slice的元素为,1,2,9,4,5
切片只能访问到其长度内的元素。试图访问超出其长度的元素将会导致语言运行时异常,如上述newSlice[3]。与切片的容量相关联的元素只能用于增长切片。在使用这部分元素前,必须将其合并到切片的长度里
append
若切片容量有余,则返回切片仅增加长度,容量不变,即相当于修改底层数组所对应的元素,会影响所有相关切片
若切片容量已满,则会新建一个底层数组(小于1000时,容量翻倍),返回的切片以该数组为底层数组,修改该数组对应的元素,不会影响原底层数组对应的其他切片
append可以增加单个元素,也可以增加多个元素,还可以增加slice
slice := []int{1,2,3,4,5} newSlice1 := append(slice,6) newSlice2 := append(slice,6,7,8) newSlice3 := append(slice,newSlice1,newSlice2)
切片迭代
- for range
for i,v := range slice{ fmt.Printf("Index: %d Value: %d Address: %X\n", i, v, &slice[i]) }
i 为元素索引,v为元素的一个副本
- for 循环
for i := 2; i < len(slice); i++ { fmt.Printf("Index: %d Value: %d\n", i, slice[i]) }
- 可以用占位符忽略返回值
内置函数 len,cap
len(slice) - 切片的长度
cap(slice) - 切片的容量
- 切片的传递
切片是一个由三个字段构成的结构体,每个字段各占8个字节,所以在函数间传递 24 字节的数据会非常快速、简单。这也就是说传递的是一个副本切片,共用同一底层函数。
- 切片与切片不能直接用
==
比较,唯一能与切片比较的是nil