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个赞
切片值只是标头,指向后备数组。切片头只包含指针。所以当你复制一个切片值时,副本也会指向同一个后备数组。因此,如果您通过原始切片标头更改支持数组,则副本也会观察到更改。
这就是你的情况。你分配area1
给area2
. 单元格是一个切片数组。因此将复制数组,其中包含切片标头,因此将复制切片标头。切片头包含指向支持数组的指针,支持数组不会被复制。
所以只有一个支持数组来保存[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),但您的循环变量不会考虑到这一点。最容易处理的是使用向下循环。
- 1 回答
- 0 关注
- 117 浏览
添加回答
举报
0/150
提交
取消