切片基础 #
一、切片概述 #
切片是对底层数组的引用,提供动态大小的视图。
1.1 切片特点 #
- 动态长度
- 引用类型
- 包含指针、长度、容量
1.2 切片结构 #
text
type slice struct {
ptr *T // 指向底层数组
len int // 长度
cap int // 容量
}
二、切片声明 #
2.1 声明未初始化 #
go
var s []int
fmt.Println(s) // []
fmt.Println(s == nil) // true
2.2 字面量初始化 #
go
s := []int{1, 2, 3, 4, 5}
fmt.Println(s) // [1 2 3 4 5]
2.3 从数组创建 #
go
arr := [5]int{1, 2, 3, 4, 5}
s1 := arr[:] // 全部
s2 := arr[1:3] // [2 3]
s3 := arr[:3] // [1 2 3]
s4 := arr[2:] // [3 4 5]
2.4 make函数 #
go
s := make([]int, 5) // len=5, cap=5
s := make([]int, 5, 10) // len=5, cap=10
三、len和cap #
3.1 len函数 #
返回切片长度(元素个数):
go
s := []int{1, 2, 3, 4, 5}
fmt.Println(len(s)) // 5
3.2 cap函数 #
返回切片容量(底层数组大小):
go
s := make([]int, 5, 10)
fmt.Println(len(s)) // 5
fmt.Println(cap(s)) // 10
3.3 切片表达式与容量 #
go
arr := [5]int{1, 2, 3, 4, 5}
s := arr[1:3]
fmt.Println(len(s)) // 2
fmt.Println(cap(s)) // 4(从索引1到数组末尾)
四、切片操作 #
4.1 访问元素 #
go
s := []int{1, 2, 3, 4, 5}
fmt.Println(s[0]) // 1
fmt.Println(s[4]) // 5
4.2 修改元素 #
go
s := []int{1, 2, 3, 4, 5}
s[0] = 10
fmt.Println(s) // [10 2 3 4 5]
4.3 切片表达式 #
go
s := []int{1, 2, 3, 4, 5}
s1 := s[1:3] // [2 3]
s2 := s[:3] // [1 2 3]
s3 := s[2:] // [3 4 5]
s4 := s[:] // [1 2 3 4 5]
4.4 完整切片表达式 #
限制新切片的容量:
go
s := []int{1, 2, 3, 4, 5}
s1 := s[1:3:3] // len=2, cap=2
fmt.Println(len(s1)) // 2
fmt.Println(cap(s1)) // 2
五、切片遍历 #
5.1 for循环 #
go
s := []int{1, 2, 3, 4, 5}
for i := 0; i < len(s); i++ {
fmt.Println(s[i])
}
5.2 for-range #
go
s := []int{1, 2, 3, 4, 5}
for index, value := range s {
fmt.Printf("s[%d] = %d\n", index, value)
}
六、nil切片和空切片 #
6.1 nil切片 #
go
var s []int
fmt.Println(s == nil) // true
fmt.Println(len(s)) // 0
fmt.Println(cap(s)) // 0
6.2 空切片 #
go
s := []int{}
fmt.Println(s == nil) // false
fmt.Println(len(s)) // 0
fmt.Println(cap(s)) // 0
s2 := make([]int, 0)
fmt.Println(s2 == nil) // false
6.3 区别 #
| 类型 | nil检查 | len | cap |
|---|---|---|---|
| nil切片 | true | 0 | 0 |
| 空切片 | false | 0 | 0 |
七、切片是引用类型 #
7.1 赋值共享底层数组 #
go
s1 := []int{1, 2, 3, 4, 5}
s2 := s1
s2[0] = 10
fmt.Println(s1) // [10 2 3 4 5]
fmt.Println(s2) // [10 2 3 4 5]
7.2 切片共享底层数组 #
go
s1 := []int{1, 2, 3, 4, 5}
s2 := s1[1:3]
s2[0] = 20
fmt.Println(s1) // [1 20 3 4 5]
fmt.Println(s2) // [20 3]
7.3 函数传参 #
go
func modify(s []int) {
s[0] = 10
}
func main() {
s := []int{1, 2, 3}
modify(s)
fmt.Println(s) // [10 2 3]
}
八、实际应用 #
8.1 处理数据流 #
go
func processStream(data []byte) {
for len(data) > 0 {
chunk := data[:min(len(data), 1024)]
process(chunk)
data = data[len(chunk):]
}
}
8.2 分页 #
go
func paginate(items []Item, page, pageSize int) []Item {
start := (page - 1) * pageSize
if start >= len(items) {
return nil
}
end := start + pageSize
if end > len(items) {
end = len(items)
}
return items[start:end]
}
8.3 缓冲区 #
go
func readLines(r io.Reader) []string {
var lines []string
scanner := bufio.NewScanner(r)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines
}
九、最佳实践 #
9.1 预分配容量 #
go
// 好:预分配
s := make([]int, 0, 100)
for i := 0; i < 100; i++ {
s = append(s, i)
}
// 不好:频繁扩容
var s []int
for i := 0; i < 100; i++ {
s = append(s, i)
}
9.2 检查nil #
go
func process(s []int) {
if s == nil {
return
}
// 处理...
}
9.3 使用make初始化 #
go
// 好:明确容量
s := make([]int, 0, 10)
// 也可以
s := []int{}
十、总结 #
切片要点:
| 特性 | 说明 |
|---|---|
| 声明 | []T |
| 创建 | 字面量、make、从数组 |
| 类型 | 引用类型 |
| 长度 | len() |
| 容量 | cap() |
关键点:
- 引用类型:切片共享底层数组
- 动态大小:长度可变
- len和cap:长度是元素个数,容量是底层数组大小
- nil vs 空:nil切片和空切片不同
- make函数:推荐使用make预分配
准备好学习切片操作了吗?让我们进入下一章!
最后更新:2026-03-26