arrays - 删除 slice 中的元素

标签 arrays go slice

Go 不提供任何高级函数来从 slice 中删除元素。我编写了一个函数,以此处通常建议的方式从 slice 中删除给定值,但它产生了意想不到的结果。

package main

import "fmt"

type Area struct {
    Cells [2][]uint8
}
func main() {
    var area1 Area
    area1.Cells[1] = []uint8 {5, 6, 7}

    area2 := area1

    area1.Cells[1] = removeValueFromCell(area1.Cells[1], 6)

    fmt.Println(area1.Cells[1])
    fmt.Println(area2.Cells[1])
}


func removeValueFromCell(cell []uint8, value uint8) []uint8{
    var res = cell
    for i := 0; i < len(cell); i++ {
        if cell[i] == value {
            res = append(cell[:i], cell[i+1:]...)
        }
    }
    return res
}

这个程序输出:

[5 7] <- as expected

[5 7 7] <- why not [5 6 7] or [5 7] ?

最佳答案

slice 值只是 header ,指向后备数组。 slice 头只包含指针。所以当你复制一个 slice 值时,副本也会指向同一个后备数组。因此,如果您通过原始 slice header 更改支持数组,副本也会观察到更改。

这就是您的情况。您将 area1 分配给 area2。单元格是一个 slice 数组。因此将复制数组,其中包含 slice header ,因此将复制 slice header 。 slice 头包含指向支持数组的指针,支持数组不会被复制。

因此只有一个后备数组包含 [5, 6, 7] 元素。然后调用 removeValueFromCell(),它会修改这个支持数组:

Before:
[5, 6, 7]
After:
[5, 7, 7]

因为元素 6 已被删除,并且 slice 的其余部分(元素 [7])被复制以代替删除的元素。

然后您将这个新的 slice header (正确地只包含 2 个元素)分配给 area1.Cells[1]

但是 slice 值 area2.Cells[1] 指向同一个后备数组,并且由于您没有触及这个 slice 值,它的长度仍然是 3,因此它将看到所有后备数组已更改的元素:[5, 7, 7]

另请注意,您对 removeValueFromCell() 的实现是错误的,因为如果可移动元素在 slice 中多次列出,它的行为将不正确。这样做的原因是因为当您删除一个元素时,后续元素的索引会移动(减少 1),但您的循环变量不会考虑到这一点。最容易处理的是使用向下循环。有关详细信息,请参阅 How to remove element of struct array in loop in golang .

关于arrays - 删除 slice 中的元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52094061/

相关文章:

java - (java) - 将输入文件中的每个单词存储在字符串数组中

C++ 3d数组

Golang 在另一个 for 循环中退出 bufio for 循环

go - 是否有必要实现 Scanner 接口(interface)和 Valuer 接口(interface)

matlab - MATLAB 中冒号运算的组合

pointers - 附加到其他 slice 内的结构上的 slice 不持久

java - 检测原始 Java 数组中的重复值

Java 空指针异常

go - protoc 命令不适用于 go generate

python - 对 numpy 数组进行切片以选择列表中包含值的行。真值误差