切片基础 #

一、切片概述 #

切片是对底层数组的引用,提供动态大小的视图。

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()

关键点:

  1. 引用类型:切片共享底层数组
  2. 动态大小:长度可变
  3. len和cap:长度是元素个数,容量是底层数组大小
  4. nil vs 空:nil切片和空切片不同
  5. make函数:推荐使用make预分配

准备好学习切片操作了吗?让我们进入下一章!

最后更新:2026-03-26