Go 语言切片(Slice)
                           
天天向上
发布: 2025-03-25 23:53:24

原创
207 人浏览过

切片(slice)是 Go 语言中一种重要的数据类型,它是一种动态数组,比数组更灵活。与数组不同,切片的长度是可以改变的,允许高效地动态管理数据。切片通常用于操作和处理数据集合。


1. 切片的基本概念

切片是对数组的一个抽象,它提供了更灵活的操作方式。切片并不存储数据,而是引用底层数组的一段连续内存区域。切片的容量和长度是动态的,可以根据需要进行扩展。

1.1 切片的构成

切片包含三个字段:

  • 指针(Pointer):指向底层数组的某个位置。
  • 长度(Length):切片的元素数量。
  • 容量(Capacity):从切片的开始位置到底层数组的末尾可用元素的数量。

2. 切片的创建

2.1 使用 make 创建切片

可以通过 make 函数创建切片,make 函数接受三个参数:切片的类型、切片的长度和切片的容量。

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

slice2 := make([]int, 5, 10)  // 长度为 5,容量为 10
fmt.Println(slice2)  // 输出:[0 0 0 0 0]

2.2 使用数组字面量创建切片

可以通过数组字面量直接创建一个切片,并初始化元素值。

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

2.3 从数组中创建切片

从一个数组中创建切片,通过指定一个切片范围。

arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4]  // 从索引 1 到 3 的元素(不包括索引 4)
fmt.Println(slice)  // 输出:[2 3 4]

3. 切片的基本操作

3.1 访问和修改切片元素

可以使用索引访问和修改切片的元素。

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

slice[1] = 20
fmt.Println(slice)  // 输出:[1 20 3]

3.2 切片的长度和容量

  • 长度(Length):使用 len() 函数获取切片的长度。
  • 容量(Capacity):使用 cap() 函数获取切片的容量。
slice := []int{1, 2, 3, 4, 5}
fmt.Println(len(slice))  // 输出:5
fmt.Println(cap(slice))  // 输出:5

slice2 := make([]int, 3, 5)
fmt.Println(len(slice2))  // 输出:3
fmt.Println(cap(slice2))  // 输出:5

3.3 切片的追加操作(append

使用 append 函数向切片末尾追加元素。如果切片的容量不足以容纳新元素,Go 会自动扩展切片的容量。

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

slice = append(slice, []int{6, 7}...)
fmt.Println(slice)  // 输出:[1 2 3 4 5 6 7]
  • append(slice, 4, 5) 直接添加元素。
  • append(slice, []int{6, 7}...) 使用切片展开操作符 ... 来追加另一个切片的元素。

3.4 切片的删除操作

Go 并没有内置的删除函数,但可以通过切片的组合来模拟删除操作。

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

通过切片的组合,将删除索引为 2 的元素(即 3)。


4. 切片的性能

切片的扩展是一个性能关键点。当切片的容量不够时,append 操作会导致切片重新分配内存,这可能会引发性能问题。Go 通过指数增长来扩展切片的容量,通常是将容量扩展为原来的 2 倍。

slice := make([]int, 0, 2)
for i := 0; i < 10; i++ {
    slice = append(slice, i)
    fmt.Printf("len: %d, cap: %d\n", len(slice), cap(slice))
}

输出会显示切片容量随着添加元素的增长情况。


5. 切片的引用特性

切片是引用类型,这意味着切片变量指向同一个底层数组。当对切片进行修改时,所有引用该底层数组的切片都会看到修改。

5.1 示例:修改切片会影响其他切片

arr := [5]int{1, 2, 3, 4, 5}
slice1 := arr[1:4]  // [2, 3, 4]
slice2 := arr[2:5]  // [3, 4, 5]

slice1[0] = 99
fmt.Println(arr)    // 输出:[1 99 3 4 5]
fmt.Println(slice2) // 输出:[99 3 4]

可以看到,修改 slice1 后,arrslice2 中的相应元素也发生了变化。


6. 切片的扩容

当通过 append 操作使得切片的容量不够时,Go 会自动扩容。扩容时会分配一个新的更大的底层数组,并将原切片的元素复制到新的数组中。这时原切片的底层数组就不再与新切片共享内存。


7. 总结

  • 切片 是 Go 语言中比数组更灵活的动态数据结构,可以动态增减长度。
  • 切片通过 make 函数创建,也可以通过字面量和数组创建。
  • 切片的底层数据是数组,具有 长度容量 属性,使用 len()cap() 函数分别访问。
  • 切片是 引用类型,多个切片可以共享底层数组。
  • append() 函数用于向切片末尾添加元素,并可能导致切片扩容。
  • 切片具有内存管理的优化,能够高效地操作数据集合。

🔹 参考资料

发表回复 0

Your email address will not be published. Required fields are marked *