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 關注
- 144 瀏覽
添加回答
舉報
0/150
提交
取消