切割出的 slice 預設 cap 吃到底,append 會寫進鄰居的地盤

把一份資料切成前半與後半,只 append 前半——後半的內容會被寫壞。因為切出來的 slice 預設 cap 一路吃到 array 結尾,前半的「還能往右寫」的範圍,正好就是後半的地盤。

path := []byte("AAAA/BBBBBBBBB")
sepIndex := bytes.IndexByte(path, '/')   // 4
 
dir1 := path[:sepIndex]     // len=4  cap=14   ← cap 吃到底
dir2 := path[sepIndex+1:]   // len=9  cap=9
 
dir1 = append(dir1, "suffix"...)
// dir1 → AAAAsuffix
// dir2 → uffixBBBB        ← 只動 dir1,dir2 卻壞了
        01234567890123
path    AAAA/BBBBBBBBB
dir1    AAAA
dir2         BBBBBBBBB
--- append 後 ---
dir1    AAAAsuffix
dir2         uffixBBBB

dir1 的 cap 是 14,append 6 個字元沒超過,於是 就地寫入——寫進的正是 dir2 看的那段記憶體。

解法:full slice expression input[low:high:max]

第三個數把 cap 限成 max - low

dir1 := path[:sepIndex:sepIndex]   // len=4 cap=4

它不是「當下複製一份出來」。 這一行沒有配置任何記憶體、沒有複製任何東西,指標仍指向同一塊 array 的同一個位置;它只是把 cap 寫死,等於預先設下一道路障:下一次 append 必然超過 cap,被迫 relocate,這時才真的搬家。

寫法何時配置新記憶體結果
path[:4](cap=14)append 6 個字元不會配置寫進鄰居的地盤 💥
path[:4:4](cap=4)append 時必定配置兩者從此無關 ✅
copy 到新 slice當下就配置 + 複製兩者從此無關 ✅

要「當下就複製」得用 copy;full slice expression 只是把複製推遲到 append 那一刻,並保證它會發生

另一個副作用:擋住 GC

只取原 slice 的一小段,其餘元素仍活在同一塊底層 array 裡,整個 array 都不能被回收。只需要一小部分時,該用 copy 產生新的 slice 與新的 array。

相關:Go 的切割上限是 cap 而不是 lenSlice 是看向底層 array 的一扇窗戶