目录
切片的基本结构
Go 语言中的切片(Slice
)是对数组的一个动态抽象,它是一个更灵活的结构,能进行动态大小的调整。切片与数组的不同之处在于它的大小不固定,并且可以根据需求进行扩展。切片包含三个主要的部分:
- 指针:指向切片数据的起始位置。
- 长度(
len
):切片当前包含的元素个数。 - 容量(
cap
):从切片的起始位置到底层数组的结尾的元素个数。
切片的创建
使用 make
函数创建切片
slice := make([]int, 5) // 创建一个长度为 5 的切片,元素类型为 int,默认值为 0
make([]T, len, cap)
用来创建一个类型为 T
,长度为 len
,容量为 cap
的切片。如果 cap
被省略,则容量与长度相同。
通过数组创建切片
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // 创建一个切片,包含 arr[1], arr[2], arr[3],即 [2, 3, 4]
arr[start:end]
通过指定开始和结束索引来创建切片(end
索引是不包含的)。
使用字面量创建切片
slice := []int{1, 2, 3, 4, 5}
字面量创建并初始化一个切片。
切片的操作
切片的扩展
切片可以通过 append()
函数来扩展:
slice := []int{1, 2, 3}
slice = append(slice, 4, 5) // 添加元素 4 和 5,slice 变为 [1, 2, 3, 4, 5]
append()
函数会返回一个新的切片。如果原切片的容量不够,Go 会为切片分配一个新的底层数组。
切片的删除
删除切片中的元素可以通过切片重组的方式来实现:
slice := []int{1, 2, 3, 4, 5}
slice = append(slice[:2], slice[3:]...) // 删除索引 2 的元素,结果为 [1, 2, 4, 5]
使用 ...
展开切片。
取切片的子集
slice := []int{1, 2, 3, 4, 5}
subslice := slice[1:4] // [2, 3, 4]
切片从原始切片中提取子切片。
切片的容量
切片的容量决定了它能够容纳多少元素。可以通过 cap()
函数查看切片的容量:
slice := make([]int, 5, 10) // 创建长度为 5,容量为 10 的切片
fmt.Println(len(slice)) // 输出 5
fmt.Println(cap(slice)) // 输出 10
切片的引用特性
切片是引用类型,切片赋值不会复制底层数组,而是会共享底层数组的指针。这意味着修改一个切片会影响到其他共享相同底层数组的切片。
slice1 := []int{1, 2, 3}
slice2 := slice1
slice2[0] = 100
fmt.Println(slice1) // [100, 2, 3]
fmt.Println(slice2) // [100, 2, 3]
切片的常见问题
切片扩展时的内存管理
每当切片的容量不足时,Go 会创建一个新的更大的切片(通常是原容量的两倍),并将元素从旧切片复制到新切片中。这个过程会消耗性能,特别是在频繁扩展切片时。
共享底层数组
多个切片可以共享同一个底层数组,在这种情况下,修改一个切片会影响到其他切片。这在并发环境下可能引发数据竞争问题,因此需要小心处理。
slice1 := []int{1, 2, 3}
slice2 := slice1[:]
slice1[0] = 10
fmt.Println(slice1) // [10, 2, 3]
fmt.Println(slice2) // [10, 2, 3]
总结
Go 语言中的切片(Slice)提供了一种非常强大且灵活的数据结构,允许开发者进行动态数组操作。切片的引用特性、扩展能力以及简便的子切片操作,使得切片成为 Go 语言中最常用的数据类型之一。
发表回复