首页 > 解决方案 > 从切片中删除元素不起作用

问题描述

我想从切片中删除一些元素,但它不起作用。

package main

import (
    "fmt"
)

func main() {
    a := []string{"a", "b", "c"}
    for _, command := range a {
        if command == "a" || command == "b" || command == "c" {
            a = deleteSlice(a, command)
        }
    }
    fmt.Println(a)
}
func deleteSlice(strings []string, str string) []string {
    out := strings[:0]
    for _, s := range strings {
        if s != str {
            out = append(out, s)
        }
    }
    return out
}

预期的结果是[],但[b]实际上是。有人告诉我原因吗?

标签: arraysgoslice

解决方案


该行为的根本原因是在内部deleteSlice(),您没有分配新的后备数组,而是重用了传递给它的切片的后备数组,因为您将结果构建在strings[:0].

切片有一个支持数组。在您的代码中,当您初始化a包含以下元素的复合文字时,这种支持数组有一个单独的分配:

array = ["a", "b", "c"]

所以 firstdeleteSlice()被调用 with "a",它在其中,所以它不会被重新添加。第一次迭代后,支持数组如下所示:

array = ["b", "c", "c"]
        [        ]               <- returned out slice covers this

后备数组仍然包含 3 个元素,但切片仅覆盖前 2 个元素。

main 中的循环继续进行下一次迭代(索引 = 1),循环迭代的切片覆盖整个后备数组(其中使用的切片for rage仅计算一次!),因此后备数组中索引 1 处的元素是现在是“c”。这被传递给deleteSlice(). deleteSlice()删除"c"元素,后备数组不会改变(没有元素要追加"c"):

array = ["b", "c", "c"]
        [   ]                    <- returned out slice covers this

并且返回的切片长度为 1(后备数组的第一个元素。

main 中的循环进行到最后一次迭代:索引 = 2。后备数组在索引 2 处具有元素“c”,该元素被传递给deleteSlice(). 该元素不包含在切片中(覆盖单个["b"]元素),因此返回。

查看相关问题:

删除 for 中的切片元素

删除切片中的元素

建议阅读:

Go 博客:数组、切片(和字符串):“追加”的机制

Go 博客:Go Slices:用法和内部结构

Go Wiki:切片技巧


推荐阅读