You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang移除切片相同元素遇索引越界panic,求两种实现方案

问题描述

现有两个rune切片:

a := []rune("/storage/emulated/0/Custom_Scripts/Golang/")
b := []rune("/storage/emulated/0/")

需求:从切片a中移除所有与切片b中元素相同的元素,仅允许引入fmt包用于打印结果,需通过两种方式实现:循环遍历、利用映射。

用户自行编写的循环实现代码触发索引越界panic,代码如下:

package main
import(
"fmt"
)
func main() {
    fileMeta := []rune("/storage/emulated/0/Custom_Scripts/Golang/")
    delChr := []rune("/storage/emulated/0")
    for i, j := range fileMeta {
        for _, m := range delChr {
            if m == j {
               //fileMeta[i] = ""
               fileMeta = append(fileMeta[:i], fileMeta[i+1:]...)
            }
        }
    }
    fmt.Println(fileMeta)
}  

错误原因分析

你代码里的索引越界panic,根源是在遍历原切片的同时直接修改切片长度:

  • range fileMeta是基于切片初始长度生成的遍历序列,当你用append(fileMeta[:i], fileMeta[i+1:]...)删除元素时,切片fileMeta的长度会缩短。
  • 遍历到后期,原来的索引i会超过新切片的长度,导致访问fileMeta[i+1:]时触发越界。
  • 另外,即使没触发越界,删除元素后后续元素的索引会前移,继续用原来的i遍历会跳过部分元素,逻辑也不正确。

方法一:循环遍历(创建新切片收集结果)

这种方式不修改原切片,而是创建一个新切片,只保留a中不在b里的元素:

package main

import "fmt"

func main() {
    a := []rune("/storage/emulated/0/Custom_Scripts/Golang/")
    b := []rune("/storage/emulated/0/")

    // 创建新切片存储结果,预分配原切片长度的空间提升效率
    result := make([]rune, 0, len(a))
outer:
    for _, char := range a {
        // 检查当前字符是否在b中
        for _, delChar := range b {
            if char == delChar {
                // 存在则跳过,继续处理下一个字符
                continue outer
            }
        }
        // 不存在则加入结果切片
        result = append(result, char)
    }

    fmt.Println(string(result)) // 输出: Custom_Scripts/Golang
}

这里用outer标签跳出内层循环,避免重复判断,逻辑清晰且不会出现索引问题。

方法二:利用映射优化查询效率

当切片b的元素较多时,用映射可以将查询时间从O(n)降到O(1),大幅提升效率:

package main

import "fmt"

func main() {
    a := []rune("/storage/emulated/0/Custom_Scripts/Golang/")
    b := []rune("/storage/emulated/0/")

    // 将b中的元素存入map,键为rune,值为bool标记需删除
    delMap := make(map[rune]bool)
    for _, char := range b {
        delMap[char] = true
    }

    // 遍历a,收集不在删除映射中的元素
    result := make([]rune, 0, len(a))
    for _, char := range a {
        if !delMap[char] {
            result = append(result, char)
        }
    }

    fmt.Println(string(result)) // 输出: Custom_Scripts/Golang
}

这种方式先构建删除元素的映射表,再遍历原切片快速判断是否保留元素,比双重循环更高效。

内容的提问来源于stack exchange,提问作者functionX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 21:08:10