Go切片
Go切片是动态长度的引用类型,比数组更灵活常用。
slice声明与初始化
基本语法
Go
// 声明slice(nil slice)
var s []int // nil,len=0
// 直接初始化
s := []int{1, 2, 3}
// make初始化
s := make([]int, 5) // len=5, cap=5
s := make([]int, 5, 10) // len=5, cap=10
初始化对比
Go
// nil slice
var s []int
fmt.Println(s == nil) // true
// 空slice(非nil)
s := []int{}
fmt.Println(s == nil) // false
fmt.Println(len(s)) // 0
// make初始化(非nil)
s := make([]int, 0)
fmt.Println(s == nil) // false
slice基本操作
访问元素
Go
s := []int{1, 2, 3, 4, 5}
// 索引访问
fmt.Println(s[0]) // 1
fmt.Println(s[4]) // 5
// 修改元素
s[0] = 10
// 越界访问
fmt.Println(s[5]) // panic!
append添加元素
Go
s := []int{1, 2}
// 添加元素
s = append(s, 3) // [1, 2, 3]
s = append(s, 4, 5) // [1, 2, 3, 4, 5]
// 添加另一个slice
s = append(s, []int{6, 7}...) // 展开添加
append可能返回新slice,需用原变量接收。
删除元素
Go
s := []int{1, 2, 3, 4, 5}
// 删除索引2的元素
s = append(s[:2], s[3:]...)
// [1, 2, 4, 5]
// 删除第一个元素
s = s[1:]
// 删除最后一个元素
s = s[:len(s)-1]
slice截取
截取语法
Go
s := []int{0, 1, 2, 3, 4, 5}
// 截取
s[1:4] // [1, 2, 3](索引1到3)
s[:3] // [0, 1, 2](开头到索引2)
s[3:] // [3, 4, 5](索引3到结尾)
s[:] // [0, 1, 2, 3, 4, 5](全部)
// 留意:截取共享底层数组
sub := s[1:3] // sub和s共享底层数组
sub[0] = 100 // 会影响s
fmt.Println(s[1]) // 100
完整截取语法
Go
// s[low:high:max]
// low:起始索引
// high:结束索引(不含)
// max:容量限制
s := []int{0, 1, 2, 3, 4, 5}
sub := s[1:3:3] // len=2, cap=2
// 限制容量,防止append影响原数组
slice遍历
for range遍历
Go
s := []int{1, 2, 3}
for index, value := range s {
fmt.Println(index, value)
}
for _, value := range s {
fmt.Println(value)
}
for index := range s {
fmt.Println(index)
}
slice底层结构
结构示意
Go
// slice内部结构
type slice struct {
ptr *int // 指向底层数组
len int // 长度
cap int // 容量
}
容量与长度
Go
s := make([]int, 3, 10)
fmt.Println(len(s)) // 3(实际元素数)
fmt.Println(cap(s)) // 10(最大容量)
// 容量内append不扩容
s = append(s, 4, 5, 6) // cap仍10
扩容机制
Go
s := make([]int, 0, 2)
// 超过容量自动扩容
s = append(s, 1, 2) // len=2, cap=2
s = append(s, 3) // len=3, cap=4(扩容)
s = append(s, 4, 5, 6, 7) // len=7, cap=8
// 扩容规则:小于1024翻倍,大于1024增长25%
slice复制
copy函数
Go
src := []int{1, 2, 3}
dst := make([]int, 5)
n := copy(dst, src)
fmt.Println(n) // 3(复制数量)
fmt.Println(dst) // [1, 2, 3, 0, 0]
// 目标slice小于源
dst := make([]int, 2)
copy(dst, src)
fmt.Println(dst) // [1, 2](只复制2个)
slice常用操作表
| 操作 | 语法 | 说明 |
|---|---|---|
| 创建 | make([]T, len, cap) | 指定长度容量 |
| 添加 | append(s, v) | 返回新slice |
| 截取 | s[low:high] | 共享底层数组 |
| 长度 | len(s) | 元素数量 |
| 容量 | cap(s) | 最大容量 |
| 复制 | copy(dst, src) | 深拷贝 |
| 删除 | append(s[:i], s[i+1:]...) | 删除索引i |
| 清空 | s = s[:0] | 清空复用底层数组 |
slice vs 数组
| 特性 | slice | 数组 |
|---|---|---|
| 长度 | 动态(len) | 固定 |
| 类型 | []T | [N]T |
| 赋值 | 引用 | 复制 |
| 扩容 | append自动 | 不支持 |
| 零值 | nil | 元素零值 |
要点总结
- slice是动态长度的引用类型
- make初始化指定len和cap
- append添加元素,超过容量自动扩容
- 截取共享底层数组,修改相互影响
- copy深拷贝,不共享底层数组
- len获取长度,cap获取容量
- 扩容:小于1024翻倍,大于1024增25%
- slice比数组更灵活,实际项目多用slice
- s[:0]清空slice复用底层数组
📝 发现内容有误?点击此处直接编辑