为了账号安全,请及时绑定邮箱和手机立即绑定

删除切片中的元素

删除切片中的元素

Go
一只名叫tom的猫 2023-03-29 15:17:46
Go 不提供任何高级函数来从切片中删除元素。我编写了一个函数,以此处通常建议的方式从切片中删除给定值,但它产生了意想不到的结果。package mainimport "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] ?
查看完整描述

1 回答

?
湖上湖

TA贡献2003条经验 获得超2个赞

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

这就是你的情况。你分配area1area2. 单元格是一个切片数组。因此将复制数组,其中包含切片标头,因此将复制切片标头。切片头包含指向支持数组的指针,支持数组不会被复制。

所以只有一个支持数组来保存[5, 6, 7]元素。然后调用removeValueFromCell(),它会修改这个后备数组:

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

因为该元素6已被删除,所以切片的其余部分(元素[7])被复制以代替被删除的元素。

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

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

另请注意,您的 实现removeValueFromCell()是错误的,因为如果可移动元素在切片中多次列出,它的行为将不正确。这样做的原因是因为当您删除一个元素时,后续元素的索引会移动(减少 1),但您的循环变量不会考虑到这一点。最容易处理的是使用向下循环。


查看完整回答
反对 回复 2023-03-29
  • 1 回答
  • 0 关注
  • 103 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信