资讯中心

6.3 Go 切片技巧学习笔记

📅 2026/8/28 7:42:18
6.3 Go 切片技巧学习笔记
6.3 Go 切片技巧学习笔记1. 删除指定索引的元素 — append 切片拼接Go 没有内置的删除元素操作用append把前半段和后半段拼接起来packagemainimportfmtfuncmain(){data:[]int{1,2,3,4,5,6,7,8,9,10}// 删除索引3的元素值4// append(data[:3], data[4:]...) → [1,2,3] [5,6,7,8,9,10]index:3dataappend(data[:index],data[index1:]...)fmt.Println(After removing index 3:,data)}执行结果After removing index 3: [1 2 3 5 6 7 8 9 10]要点data[:index]— 索引之前的元素[1, 2, 3]data[index1:]— 索引之后的元素[5, 6, 7, 8, 9, 10]append(data[:index], data[index1:]...)— 把两段拼接中间的元素 4 被删除这是 Go 删除切片元素的标准模式append 前半段 后半段注意这个操作修改了底层数组删除后 data 的长度变短但底层数组末尾仍有一个残留元素原 data[9]10 被复制到新位置旧位置仍有值只是不可访问如果元素是指针类型或包含指针需先置 nil 防止内存泄漏data[index]nil// 先置空再 appenddataappend(data[:index],data[index1:]...)2. 在指定索引插入元素 — 双层 append插入元素也用 append分三步取前半段 → append 新值 → append 后半段packagemainimportfmtfuncmain(){data:[]int{1,2,3,5,6,7,8,9,10}// 删除4之后的切片// 在索引2处插入值99insertIndex:2insertValue:99// 步骤拆解// 1. append(data[:2], 99) → [1, 2, 99]// 2. append([1, 2, 99], data[2:]...) → [1, 2, 99, 3, 5, 6, 7, 8, 9, 10]dataappend(append(data[:insertIndex],insertValue),data[insertIndex:]...)fmt.Println(After inserting 99 at index 2:,data)}执行结果After inserting 99 at index 2: [1 2 99 99 5 6 7 8 9 10]要点append(data[:insertIndex], insertValue)— 在前半段末尾追加新值得到 [1, 2, 99]append([1,2,99], data[insertIndex:]...)— 拼接后半段得到 [1, 2, 99, 3, 5, …]双层 append 嵌套内层 append 返回的切片作为外层 append 的第一个参数注意输出中有两个 99这是因为内层append(data[:2], 99)在原底层数组上操作data[:2] [1, 2]append 99 后底层位置 data[2] 被写为 99外层append([1,2,99], data[2:]...)中data[2:]从原底层数组读取data[2] 已经是 99所以出现了两个 99 — 这是 append 在共享底层数组上操作的副作用更安全的做法先复制前半段到新切片避免修改原底层数组// 安全版本使用临时切片temp:make([]int,insertIndex)copy(temp,data[:insertIndex])tempappend(temp,insertValue)dataappend(temp,data[insertIndex:]...)3. 原地反转切片 — 双指针交换用两个指针从两端向中间交换元素时间复杂度 O(n)空间复杂度 O(1)packagemainimportfmtfuncmain(){numbers:[]int{1,2,3,4,5}// 双指针i 从头开始j 从尾开始交换后 i j--fori,j:0,len(numbers)-1;ij;i,ji1,j-1{numbers[i],numbers[j]numbers[j],numbers[i]}fmt.Println(Reversed numbers:,numbers)}执行结果Reversed numbers: [5 4 3 2 1]要点for i, j : 0, len(numbers)-1; i j; i, j i1, j-1— 初始化两个指针i j-- 同时更新numbers[i], numbers[j] numbers[j], numbers[i]— Go 的多重赋值同时交换两个元素i j— 当 i 和 j 相遇或越过时停止奇数长度时中间元素不交换原地操作不需要额外空间直接在原切片上交换交换过程1↔5 → 2↔4 → 3不动中间→ 结果 [5, 4, 3, 2, 1]Go 没有内置的反转函数这是反转切片的标准写法Go 官方 Wiki 推荐4. 过滤删除所有指定值 — append 收集保留值遍历切片把不等于目标值的元素收集到新切片packagemainimportfmtfuncmain(){values:[]int{1,2,3,2,4,2,5}target:2// 创建新切片收集非目标值varfiltered[]intfor_,v:rangevalues{ifv!target{filteredappend(filtered,v)}}fmt.Printf(After removing all %d: %v\n,target,filtered)}执行结果After removing all 2: [1 3 4 5]要点var filtered []int— nil 切片append 自动分配底层数组遍历原切片v ! target时 append 到新切片结果[1, 3, 4, 5]— 所有 2 被移除这是过滤模式遍历 条件判断 appendGo 中极常用更高效的就地版本不分配新底层数组n:0for_,v:rangevalues{ifv!target{values[n]v n}}valuesvalues[:n]// 截断到新长度5. 检查切片是否包含某值 — 手动遍历Go 1.18 之前没有内置的contains函数需要手动遍历Go 1.21 有slices.Containspackagemainimportfmtfuncmain(){haystack:[]string{apple,banana,cherry,date}needle:cherryvarfoundboolfor_,item:rangehaystack{ifitemneedle{foundtruebreak// 找到后立即退出}}iffound{fmt.Printf(Found %s in slice\n,needle)}else{fmt.Printf(%s not found in slice\n,needle)}}执行结果Found cherry in slice要点遍历切片逐个比较break找到后立即退出var found bool— 默认值 false找到后设为 trueGo 1.21 可以用slices.Contains(haystack, needle)更简洁importgolang.org/x/exp/slices// 或 Go 1.21: slicesfound:slices.Contains(haystack,needle)对于排序切片可以用二分搜索提高效率sort.SearchStrings(slice, target)6. 去重 — map 记录已见元素用 map 的键来跟踪哪些元素已经出现过实现去重packagemainimportfmtfuncmain(){duplicates:[]int{1,2,2,3,1,4,3,5}// map 记录已见元素只保留首次出现的seen:make(map[int]bool)varunique[]intfor_,v:rangeduplicates{if!seen[v]{// v 还没出现过seen[v]true// 标记为已见uniqueappend(unique,v)// 加入结果}}fmt.Println(Unique elements:,unique)}执行结果Unique elements: [1 2 3 4 5]要点seen : make(map[int]bool)— map 的键是元素值bool 标记是否已见!seen[v]— v 不在 map 中 首次出现加入结果并标记seen[v] true— 标记已见下次遇到相同值时跳过结果[1, 2, 3, 4, 5]— 保持了首次出现的顺序去重效率O(n) 时间map 查找是 O(1)O(n) 空间map 和结果切片如果不关心顺序直接用 map 的键即可seen:make(map[int]struct{})// struct{} 不占内存for_,v:rangeduplicates{seen[v]struct{}{}}unique:make([]int,0,len(seen))fork:rangeseen{uniqueappend(unique,k)}// 注意map 遍历顺序不确定知识点总结知识点关键概念删除元素append(data[:i], data[i1:]...)— 前半段 后半段拼接插入元素append(append(data[:i], val), data[i:]...)— 双层 append注意底层数组副作用反转切片双指针交换for i,j : 0,len-1; ijGo 官方推荐写法过滤删除遍历 条件判断 append 收集保留值包含检查手动遍历 breakGo 1.21 用slices.Contains去重map[元素]bool记录已见保持首次出现顺序