1. 切片的定义

切片是一个可变长的序列,底层是对数组的引用。它具有以下三个属性:

  • 长度(len):切片中的元素数量。
  • 容量(cap):从切片的起始位置到底层数组末尾的元素数量。
  • 底层数组:存储切片实际数据的数组。

2. 切片的创建方式

(1)基于数组创建

arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // 包含 arr[1], arr[2], arr[3]
fmt.Println(slice) // 输出:[2 3 4]

(2)直接使用 make 函数

make 创建的切片会自动分配底层数组。

slice := make([]int, 3, 5) // 长度为 3,容量为 5
fmt.Println(slice)        // 输出:[0 0 0]
fmt.Println(len(slice))   // 输出:3
fmt.Println(cap(slice))   // 输出:5

(3)通过字面量创建

slice := []int{1, 2, 3}
fmt.Println(slice) // 输出:[1 2 3]

3. 切片的基本操作

(1)添加元素

可以使用 append 函数向切片中添加元素:

slice := []int{1, 2, 3}
slice = append(slice, 4, 5) // 添加多个元素
fmt.Println(slice)         // 输出:[1 2 3 4 5]

(2)复制切片

使用 copy 函数复制切片:

src := []int{1, 2, 3}
dst := make([]int, len(src))
copy(dst, src)
fmt.Println(dst) // 输出:[1 2 3]

(3)截取切片

通过 [start:end] 语法截取子切片:

slice := []int{1, 2, 3, 4, 5}
subSlice := slice[1:4] // 包含元素 slice[1], slice[2], slice[3]
fmt.Println(subSlice)  // 输出:[2 3 4]

4. 切片的底层原理

  • 切片是一个结构体,包含了指向底层数组的指针、切片长度和切片容量。
  • 修改切片内容会影响底层数组,从而可能影响共享同一底层数组的其他切片。
arr := [5]int{1, 2, 3, 4, 5}
slice1 := arr[1:4] // [2 3 4]
slice2 := arr[2:5] // [3 4 5]

slice1[1] = 99      // 修改 slice1 的第二个元素
fmt.Println(arr)    // 输出:[1 2 99 4 5]
fmt.Println(slice2) // 输出:[99 4 5]

5. 切片的动态扩容

  • 如果切片的容量不足以容纳新元素,append 会分配一个新的底层数组,将数据复制到新数组中。
  • 扩容的规则通常是容量的 2 倍。
slice := []int{}
for i := 1; i <= 5; i++ {
    slice = append(slice, i)
    fmt.Printf("len=%d cap=%d slice=%v\n", len(slice), cap(slice), slice)
}

输出:

len=1 cap=1 slice=[1]
len=2 cap=2 slice=[1 2]
len=3 cap=4 slice=[1 2 3]
len=4 cap=4 slice=[1 2 3 4]
len=5 cap=8 slice=[1 2 3 4 5]

6. 注意事项

  • 切片共享底层数组:多个切片可以引用同一个数组,修改其中一个切片的值会影响其他切片。
  • 避免越界错误:对切片的访问或截取要确保索引合法,否则会引发运行时错误。
  • 垃圾回收:切片引用的底层数组不会立即释放,除非切片和所有共享它的切片都被释放。

分类: Go 标签: Go

评论

暂无评论数据

暂无评论数据

目录