切片(slice)是 Go 语言中用于处理变长数据集合的核心结构,是在数组之上的一个轻量抽象,使用起来更灵活、高效,是日常开发中使用最多的数据类型之一。
一、什么是切片
切片是对数组的一个连续片段的引用,其本质是一个三元组:
- • 指向底层数组的指针
- • 切片的长度(len)
- • 切片的容量(cap)
二、切片的声明与初始化
1. 从数组或切片派生
arr := [5]int{1, 2, 3, 4, 5}
s1 := arr[1:4] // 包含索引1到3,不包含4
fmt.Println(s1) // [2 3 4]
2. 使用 make
s2 := make([]int, 3, 5) // 长度为3,容量为5
fmt.Println(s2) // [0 0 0]
3. 使用字面量
s3 := []string{"go", "java", "rust"}
三、切片的基本操作
1. 访问元素
s := []int{10, 20, 30}
fmt.Println(s[1]) // 20
2. 修改元素
s[1] = 99
3. 遍历切片
for i, v := range s {fmt.Printf("Index %d: %d\n", i, v)
}
四、切片的长度与容量
s := []int{1, 2, 3, 4, 5}
sub := s[1:3]
fmt.Println(len(sub)) // 2
fmt.Println(cap(sub)) // 4(从索引1到数组末尾)
五、切片的扩容
当切片容量不足时,使用 append
会自动扩容:
s := []int{1, 2}
s = append(s, 3, 4, 5)
fmt.Println(s) // [1 2 3 4 5]
注意: append 可能导致切片指向新的底层数组。
六、切片之间的共享与副本
多个切片可能共享同一个底层数组:
arr := [5]int{1, 2, 3, 4, 5}
s1 := arr[1:4]
s2 := arr[2:5]
s1[1] = 99
fmt.Println(arr) // [1 2 99 4 5]
fmt.Println(s2) // [99 4 5]
如果需要独立副本,可使用 copy
:
dst := make([]int, len(s1))
copy(dst, s1)
七、切片是引用类型
函数传参时,修改切片会影响原始数据(因为底层数组是共享的):
func modify(s []int) {s[0] = 100
}
a := []int{1, 2, 3}
modify(a)
fmt.Println(a) // [100 2 3]
八、删除切片元素
Go 没有内建删除函数,可以用切片拼接模拟:
s := []int{1, 2, 3, 4, 5}
i := 2 // 删除索引为2的元素
s = append(s[:i], s[i+1:]...)
fmt.Println(s) // [1 2 4 5]
九、切片陷阱:共享底层数组导致意外修改
s1 := []int{1, 2, 3, 4}
s2 := s1[:2]
s3 := append(s2, 99, 100) // 此时可能会影响 s1 的内容
使用 copy()
复制切片是解决此问题的安全做法。
十、小结
特性 | 说明 |
动态长度 | 可根据需要自动扩容 |
引用类型 | 多个切片可能共享底层数组 |
三元结构 | 指针 + 长度 + 容量 |
用途广泛 | 是数组的增强版,常用于集合处理 |
可组合使用 | 和 append 、copy 、range 搭配使用最常见 |
切片的灵活性和效率让它成为 Go 语言中处理数据集合的首选结构。理解其底层原理能帮助你写出更高性能的代码。