数组
Go语言中,一个数组变量表示整个数组,它不是指向第一个元素的指针(不像 C 语言的数组)。 当一个数组变量被赋值或者被传递的时候,实际上会复制整个数组。
切片
切片是数组的引用
切片并不存储任何数据,它只是描述了底层数组中的一段。更改切片的元素会修改其底层数组中对应的元素。与它共享底层数组的切片都会观测到这些修改。
func main() {
names := [4]string{
"John",
"Paul",
"George",
"Ringo",
}
fmt.Println(names)// [John Paul George Ringo]
// 从数组中截取得到切片
a := names[0:2] // 截取的是 左闭右开的区间 [0,2)
b := names[1:3]
fmt.Println(a, b)// [John Paul] [Paul George]
b[0] = "XXX"// 修改
// a,b和底层数组都被修改了
fmt.Println(a, b)// [John XXX] [XXX George]
fmt.Println(names)// [John XXX George Ringo]
}
切片既可以从数组或切片中截取(截取不能超出它的容量,索引也不能为负值),也可以直接创建
切片类型的写法是 []T,像是没有指定长度的数组
letters := []string{"a", "b", "c", "d"}
切片可以使用内置函数 make 创建,函数签名为:
func make([]T, len, cap) []T // len 表示切片长度,cap表示切片底层数组的长度(可选,若不指定则于len相等)
// eg:
s := make([]byte, 5, 5)// 指定cap为5
q := make([]byte, 5)// len(s) = 5 cap(s) = 5
切片的内幕
一个切片是一个数组片段的描述。它包含了指向数组的指针,片段的长度, 和容量(片段的最大长度)。
切片的零值为 nil 。对于切片的零值, len 和 cap 都将返回0。
sl := make([]byte, 5, 5) // 0 0 0 0 0
// 此时 len(sl) == 5 cap(sl) == 5
// 截取
sl = sl[2:4] // 截取自己
此时 len(sl) == 2 cap(sl) == 3 因为cap是从切片开头到最后算的,且截取操作不可逆,无法再截取到底层数组索引为0和1的块了。
s = s[:cap(s)] // 截取后面全部
copy and append 函数
copy 函数签名: func copy(dst, src []T) int 表示将src切片的元素复制到dst,返回值是复制的元素个数。
s1 := []int{1, 3, 4, 6}
s2 := make([]int, 7)
num := copy(s2, s1)
fmt.Println(num)// 4
append 函数签名:func append(s []T, x ...T) []T , x...T表示要增加的类型为T的元素列表。
该函数将元素追加到切片尾部, 必要的话会增加切片的容量,最后返回更新的切片:
s1 := []int{1, 3} // cap(s1) == 2
s1 = append(s1, 9, 0, 90) // 容量不够,增加了容量 cap(s1) == 5 s1 == {1, 3, 9, 0, 90}
- 注意
切片操作并不会复制底层的数组。整个数组将被保存在内存中,直到它不再被引用。 有时候可能会因为一个小的内存引用导致保存所有的数据。就是说,如果一个切片中有很多数据,其中个别数据被其他变量引用会导致整个切片都存在内存中,占用较大内存,浪费资源。
解决方法是将要用到的数据复制到新的切片中去。
写在最后
刚开始有些不太清楚的地方,自己搞清楚之后记录下来
over~