今天学习了Go语言基础语法,其中数组和切片部分与其他语言不同,需要重点理解、输入探究。资料来自《Go 语言之旅》
数组
理解 Go 切片需要首先理解 Go 数组,本质上与 C 中的数组区别不大:
- 定义时需要长度,且长度必须是常量
- 定义后不能改变大小
除了在语法上(
[]符号需要放在类型前,类型需要放在变量后)不同之外,区别不大
切片
Go 中的切片可以理解为:数组的引用:
- 切片并不存储任何数据,它只是描述了底层数组中的一段。
- 更改切片的元素会修改其底层数组中对应的元素。
- 与它共享底层数组的切片都会观测到这些修改。
切片的使用
- 可用
[]T来表示元素类型为 T 的切片类型 - 切片通过两个下标来界定,即一个上界和一个下界,二者以冒号分隔:
它会选择一个半开区间,包括第一个元素,但排除最后一个元素。a[low : high]
切片的默认行为
在进行切片时,你可以利用它的默认行为来忽略上下界。
切片下界的默认值为 0,上界则是该切片的长度。
对于数组
var a [10]int
来说,以下切片是等价的:
a[0:10]
a[:10]
a[0:]
a[:]
切片的长度与容量
- 长度:它所包含的元素个数。可通过
len(s)获取 - 容量:从它的第一个元素开始数,到其底层数组元素末尾的个数。可通过
cap(s)获取。(注意不是底层数组的长度!)
通过几个例子理解:
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s) // len=6 cap=6 [2 3 5 7 11 13]
// 截取切片使其长度为 0
s = s[:0]
printSlice(s) // len=0 cap=6 []
// 拓展其长度
s = s[:4]
printSlice(s) // len=4 cap=6 [2 3 5 7]
// 舍弃前两个值
s = s[2:]
printSlice(s) // len=2 cap=4 [5 7] **这里cap发生变化**
// 超出范围
s = s[:5]
printSlice(s) // panic: runtime error: slice bounds out of range [:5] with capacity 4
nil 切片
切片的零值是 nil。
nil 切片的长度和容量为 0 且没有底层数组。
用 make 创建切片
make 函数会分配一个元素为零值的数组并返回一个引用了它的切片:
a := make([]int, 5) // len(a)=5
要指定它的容量,需向 make 传入第三个参数:
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:] // len(b)=4, cap(b)=4
值得一提的是,make 虽然是将数据存在堆上,但与 new 不同的是,只适用于 chan slice map 三种内置类型,且返回的并非指针而是这个类型本身。
向切片追加元素
为切片追加新的元素是种常用的操作,为此 Go 提供了内建的 append 函数。内建函数的文档对此函数有详细的介绍。
func append(s []T, vs ...T) []T
append 的第一个参数 s 是一个元素类型为 T 的切片,其余类型为 T 的值将会追加到该切片的末尾。
append 的结果是一个包含原切片所有元素加上新添加元素的切片。
当 s 的底层数组太小,不足以容纳所有给定的值时,它就会分配一个更大的数组。返回的切片会指向这个新分配的数组。