切片(Slice)是 Go 语言中最常用的数据结构之一。它比数组更灵活、更强大,是 Go 编程中处理序列数据的首选。
切片是对底层数组的引用,它有三个关键属性:
┌─────────────────────────────────────────┐
│ 切片结构 │
├─────────────────────────────────────────┤
│ 指针 (ptr) → 指向底层数组 │
│ 长度 (len) → 切片中元素的个数 │
│ 容量 (cap) → 从起始位置到底层数组末尾│
└─────────────────────────────────────────┘
| 对比项 | 数组 | 切片 |
|---|---|---|
| 长度 | 固定 | 可变 |
| 类型 | [n]T | []T |
| 传递 | 值类型(复制) | 引用类型(共享) |
| 比较 | 可比较 | 不可比较(只能与 nil 比较) |
package main
import "fmt"
func main() {
arr := [5]int{10, 20, 30, 40, 50}
s1 := arr[1:4]
s2 := arr[:3]
s3 := arr[2:]
s4 := arr[:]
fmt.Printf("arr: %v\n", arr)
fmt.Printf("s1: %v\n", s1)
fmt.Printf("s2: %v\n", s2)
fmt.Printf("s3: %v\n", s3)
fmt.Printf("s4: %v\n", s4)
}
输出:
arr: [10 20 30 40 50]
s1: [20 30 40]
s2: [10 20 30]
s3: [30 40 50]
s4: [10 20 30 40 50]
切片语法:
arr[low:high] // 从 low 到 high-1
arr[low:] // 从 low 到末尾
arr[:high] // 从开头到 high-1
arr[:] // 整个数组
package main
import "fmt"
func main() {
var s1 []int
s2 := []int{10, 20, 30}
s3 := []string{"a", "b", "c"}
fmt.Printf("s1: %v, len: %d, cap: %d\n", s1, len(s1), cap(s1))
fmt.Printf("s2: %v, len: %d, cap: %d\n", s2, len(s2), cap(s2))
fmt.Printf("s3: %v, len: %d, cap: %d\n", s3, len(s3), cap(s3))
}
输出:
s1: [], len: 0, cap: 0
s2: [10 20 30], len: 3, cap: 3
s3: [a b c], len: 3, cap: 3
package main
import "fmt"
func main() {
s1 := make([]int, 5)
s2 := make([]int, 5, 10)
fmt.Printf("s1: %v, len: %d, cap: %d\n", s1, len(s1), cap(s1))
fmt.Printf("s2: %v, len: %d, cap: %d\n", s2, len(s2), cap(s2))
}
输出:
s1: [0 0 0 0 0], len: 5, cap: 5
s2: [0 0 0 0 0], len: 5, cap: 10
make 语法:
make([]T, length)
make([]T, length, capacity)
package main
import "fmt"
func main() {
nums := []int{10, 20, 30, 40, 50}
fmt.Printf("第一个元素: %d\n", nums[0])
fmt.Printf("最后一个元素: %d\n", nums[len(nums)-1])
}
package main
import "fmt"
func main() {
nums := []int{10, 20, 30}
fmt.Printf("修改前: %v\n", nums)
nums[0] = 100
fmt.Printf("修改后: %v\n", nums)
}
package main
import "fmt"
func main() {
nums := []int{10, 20, 30, 40, 50}
fmt.Println("for 循环:")
for i := 0; i < len(nums); i++ {
fmt.Printf("索引: %d, 值: %d\n", i, nums[i])
}
fmt.Println("\nfor-range:")
for index, value := range nums {
fmt.Printf("索引: %d, 值: %d\n", index, value)
}
}
append 函数用于向切片追加元素:
package main
import "fmt"
func main() {
nums := []int{10, 20, 30}
fmt.Printf("追加前: %v, len: %d, cap: %d\n", nums, len(nums), cap(nums))
nums = append(nums, 40)
fmt.Printf("追加后: %v, len: %d, cap: %d\n", nums, len(nums), cap(nums))
}
package main
import "fmt"
func main() {
nums := []int{10, 20}
nums = append(nums, 30, 40, 50)
fmt.Printf("追加多个: %v\n", nums)
}
package main
import "fmt"
func main() {
nums1 := []int{1, 2, 3}
nums2 := []int{4, 5, 6}
nums1 = append(nums1, nums2...)
fmt.Printf("合并切片: %v\n", nums1)
}
当切片容量不足时,append 会自动扩容:
package main
import "fmt"
func main() {
nums := make([]int, 0, 2)
for i := 0; i < 10; i++ {
nums = append(nums, i)
fmt.Printf("len: %d, cap: %d, value: %v\n", len(nums), cap(nums), nums)
}
}
输出:
len: 1, cap: 2, value: [0]
len: 2, cap: 2, value: [0 1]
len: 3, cap: 4, value: [0 1 2]
len: 4, cap: 4, value: [0 1 2 3]
len: 5, cap: 8, value: [0 1 2 3 4]
...
扩容规则:容量小于 1024 时翻倍,大于 1024 时增加 25%。
copy 函数用于复制切片:
package main
import "fmt"
func main() {
src := []int{1, 2, 3}
dst := make([]int, len(src))
n := copy(dst, src)
fmt.Printf("复制了 %d 个元素\n", n)
fmt.Printf("源切片: %v\n", src)
fmt.Printf("目标切片: %v\n", dst)
dst[0] = 100
fmt.Printf("\n修改目标切片后:\n")
fmt.Printf("源切片: %v\n", src)
fmt.Printf("目标切片: %v\n", dst)
}
输出:
复制了 3 个元素
源切片: [1 2 3]
目标切片: [1 2 3]
修改目标切片后:
源切片: [1 2 3]
目标切片: [100 2 3]
Go 没有内置的删除函数,需要用 append 实现:
package main
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5}
index := 2
nums = append(nums[:index], nums[index+1:]...)
fmt.Printf("删除索引 %d 后: %v\n", index, nums)
}
输出:
删除索引 2 后: [1 2 4 5]
package main
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5}
nums = nums[1:]
fmt.Printf("删除首元素: %v\n", nums)
nums = nums[:len(nums)-1]
fmt.Printf("删除尾元素: %v\n", nums)
}
输出:
删除首元素: [2 3 4 5]
删除尾元素: [2 3 4]
package main
import "fmt"
func insert(slice []int, index, value int) []int {
slice = append(slice, 0)
copy(slice[index+1:], slice[index:])
slice[index] = value
return slice
}
func main() {
nums := []int{1, 2, 4, 5}
nums = insert(nums, 2, 3)
fmt.Printf("插入后: %v\n", nums)
}
输出:
插入后: [1 2 3 4 5]
切片是引用类型,多个切片共享底层数组:
package main
import "fmt"
func main() {
arr := [5]int{1, 2, 3, 4, 5}
s1 := arr[1:4]
s2 := arr[2:5]
fmt.Printf("arr: %v\n", arr)
fmt.Printf("s1: %v\n", s1)
fmt.Printf("s2: %v\n", s2)
s1[1] = 100
fmt.Printf("\n修改 s1[1] 后:\n")
fmt.Printf("arr: %v\n", arr)
fmt.Printf("s1: %v\n", s1)
fmt.Printf("s2: %v\n", s2)
}
输出:
arr: [1 2 3 4 5]
s1: [2 3 4]
s2: [3 4 5]
修改 s1[1] 后:
arr: [1 2 100 4 5]
s1: [2 100 4]
s2: [100 4 5]
底层数组: [1, 2, 3, 4, 5, 6, 7, 8]
↑ ↑
切片 s1: ptr───────┐ │
len = 3 │ │
cap = 5 └───┘
切片 s2: ptr────────────┘
len = 3
cap = 3
package main
import "fmt"
func main() {
var s []int
if s == nil {
fmt.Println("切片是 nil")
}
if len(s) == 0 {
fmt.Println("切片是空的")
}
}
package main
import "fmt"
func unique(slice []int) []int {
keys := make(map[int]bool)
result := []int{}
for _, v := range slice {
if !keys[v] {
keys[v] = true
result = append(result, v)
}
}
return result
}
func main() {
nums := []int{1, 2, 2, 3, 3, 3, 4, 4, 5}
fmt.Printf("原切片: %v\n", nums)
fmt.Printf("去重后: %v\n", unique(nums))
}
输出:
原切片: [1 2 2 3 3 3 4 4 5]
去重后: [1 2 3 4 5]
package main
import "fmt"
func reverse(slice []int) []int {
for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
slice[i], slice[j] = slice[j], slice[i]
}
return slice
}
func main() {
nums := []int{1, 2, 3, 4, 5}
fmt.Printf("原切片: %v\n", nums)
fmt.Printf("反转后: %v\n", reverse(nums))
}
输出:
原切片: [1 2 3 4 5]
反转后: [5 4 3 2 1]
package main
import "fmt"
func filter(slice []int, f func(int) bool) []int {
result := []int{}
for _, v := range slice {
if f(v) {
result = append(result, v)
}
}
return result
}
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
evens := filter(nums, func(n int) bool {
return n%2 == 0
})
fmt.Printf("偶数: %v\n", evens)
greaterThan5 := filter(nums, func(n int) bool {
return n > 5
})
fmt.Printf("大于 5: %v\n", greaterThan5)
}
输出:
偶数: [2 4 6 8 10]
大于 5: [6 7 8 9 10]
本章学习了 Go 语言的切片:
| 知识点 | 说明 |
|---|---|
| 创建 | []T{}, make([]T, len, cap), 从数组切片 |
| 追加 | append(slice, elements...) |
| 复制 | copy(dst, src) |
| 删除 | append(slice[:i], slice[i+1:]...) |
| 长度 | len(slice) |
| 容量 | cap(slice) |
| 类型 | 引用类型,共享底层数组 |