【Go】切片
1. 切片的定义
切片是一个可变长的序列,底层是对数组的引用。它具有以下三个属性:
- 长度(len):切片中的元素数量。
- 容量(cap):从切片的起始位置到底层数组末尾的元素数量。
- 底层数组:存储切片实际数据的数组。
2. 切片的创建方式
(1)基于数组创建
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // 包含 arr[1], arr[2], arr[3]
fmt.Println(slice) // 输出:[2 3 4]
(2)直接使用 make
函数
make
创建的切片会自动分配底层数组。
slice := make([]int, 3, 5) // 长度为 3,容量为 5
fmt.Println(slice) // 输出:[0 0 0]
fmt.Println(len(slice)) // 输出:3
fmt.Println(cap(slice)) // 输出:5
(3)通过字面量创建
slice := []int{1, 2, 3}
fmt.Println(slice) // 输出:[1 2 3]
3. 切片的基本操作
(1)添加元素
可以使用 append
函数向切片中添加元素:
slice := []int{1, 2, 3}
slice = append(slice, 4, 5) // 添加多个元素
fmt.Println(slice) // 输出:[1 2 3 4 5]
(2)复制切片
使用 copy
函数复制切片:
src := []int{1, 2, 3}
dst := make([]int, len(src))
copy(dst, src)
fmt.Println(dst) // 输出:[1 2 3]
(3)截取切片
通过 [start:end]
语法截取子切片:
slice := []int{1, 2, 3, 4, 5}
subSlice := slice[1:4] // 包含元素 slice[1], slice[2], slice[3]
fmt.Println(subSlice) // 输出:[2 3 4]
4. 切片的底层原理
- 切片是一个结构体,包含了指向底层数组的指针、切片长度和切片容量。
- 修改切片内容会影响底层数组,从而可能影响共享同一底层数组的其他切片。
arr := [5]int{1, 2, 3, 4, 5}
slice1 := arr[1:4] // [2 3 4]
slice2 := arr[2:5] // [3 4 5]
slice1[1] = 99 // 修改 slice1 的第二个元素
fmt.Println(arr) // 输出:[1 2 99 4 5]
fmt.Println(slice2) // 输出:[99 4 5]
5. 切片的动态扩容
- 如果切片的容量不足以容纳新元素,
append
会分配一个新的底层数组,将数据复制到新数组中。 - 扩容的规则通常是容量的 2 倍。
slice := []int{}
for i := 1; i <= 5; i++ {
slice = append(slice, i)
fmt.Printf("len=%d cap=%d slice=%v\n", len(slice), cap(slice), slice)
}
输出:
len=1 cap=1 slice=[1]
len=2 cap=2 slice=[1 2]
len=3 cap=4 slice=[1 2 3]
len=4 cap=4 slice=[1 2 3 4]
len=5 cap=8 slice=[1 2 3 4 5]
6. 注意事项
- 切片共享底层数组:多个切片可以引用同一个数组,修改其中一个切片的值会影响其他切片。
- 避免越界错误:对切片的访问或截取要确保索引合法,否则会引发运行时错误。
- 垃圾回收:切片引用的底层数组不会立即释放,除非切片和所有共享它的切片都被释放。
版权申明
本文系作者 @hayaizo 原创发布在Hello World站点。未经许可,禁止转载。
暂无评论数据