Go语言之切片的原理与用法 - 《Go语言实战指南》

274 阅读2分钟

切片(slice)是 Go 语言中用于处理变长数据集合的核心结构,是在数组之上的一个轻量抽象,使用起来更灵活、高效,是日常开发中使用最多的数据类型之一。


一、什么是切片

切片是对数组的一个连续片段的引用,其本质是一个三元组

  • • 指向底层数组的指针
  • • 切片的长度(len)
  • • 切片的容量(cap)

二、切片的声明与初始化

1. 从数组或切片派生

arr := [5]int{12345}
s1 := arr[1:4// 包含索引1到3,不包含4
fmt.Println(s1) // [2 3 4]

2. 使用 make

s2 := make([]int35// 长度为3,容量为5
fmt.Println(s2) // [0 0 0]

3. 使用字面量

s3 := []string{"go""java""rust"}

三、切片的基本操作

1. 访问元素

s := []int{102030}
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{12345}
sub := s[1:3]
fmt.Println(len(sub)) // 2
fmt.Println(cap(sub)) // 4(从索引1到数组末尾)

五、切片的扩容

当切片容量不足时,使用 append 会自动扩容:

s := []int{12}
s = append(s, 345)
fmt.Println(s) // [1 2 3 4 5]

注意:  append 可能导致切片指向新的底层数组。


六、切片之间的共享与副本

多个切片可能共享同一个底层数组:

arr := [5]int{12345}
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([]intlen(s1))
copy(dst, s1)

七、切片是引用类型

函数传参时,修改切片会影响原始数据(因为底层数组是共享的):

func modify(s []int) {
    s[0] = 100
}
a := []int{123}
modify(a)
fmt.Println(a) // [100 2 3]

八、删除切片元素

Go 没有内建删除函数,可以用切片拼接模拟:

s := []int{12345}
i := 2 // 删除索引为2的元素
s = append(s[:i], s[i+1:]...)
fmt.Println(s) // [1 2 4 5]

九、切片陷阱:共享底层数组导致意外修改

s1 := []int{1234}
s2 := s1[:2]
s3 := append(s2, 99100// 此时可能会影响 s1 的内容

使用 copy() 复制切片是解决此问题的安全做法。


十、小结

特性说明
动态长度可根据需要自动扩容
引用类型多个切片可能共享底层数组
三元结构指针 + 长度 + 容量
用途广泛是数组的增强版,常用于集合处理
可组合使用和 appendcopyrange 搭配使用最常见

切片的灵活性和效率让它成为 Go 语言中处理数据集合的首选结构。理解其底层原理能帮助你写出更高性能的代码。