Slice 是看向底層 array 的一扇窗戶

Slice 本身不存資料。它是一個三欄位的小結構(slice header),資料躺在它指向的那塊 array 裡。

slice header = { ptr → 底層 array 的某個位置, len, cap }
  • ptr — 指向底層 array 的起點(是這個 slice 的起點,不一定是 array 的起點)
  • len — 這扇窗戶目前看得到幾個元素
  • cap — 從自己的起點算到底層 array 的最後,最多還能往右拉多寬

len 與 cap 管的是兩件不同的事:一個是「現在看得到多少」,一個是「最多允許碰到哪裡」。後者才是所有詭異行為的根源。

s := []int{2, 3, 5, 7, 11, 13}   // len=6 cap=6
 
s = s[:0]    // len=0 cap=6 []
s = s[:4]    // len=4 cap=6 [2 3 5 7]
s = s[2:]    // len=2 cap=4 [5 7]   ← 起點右移,cap 跟著變小

起點一往右移,左邊的元素就再也拿不回來——slice 只能向右擴展,不能向左

為什麼需要 slice 而不是直接用 array

Go 的 array 長度是型別的一部分[4]int[5]int 是不同型別),開好就不能改;而且 array 是值型別,賦值與傳參都會整份複製

slice 把「多長」從型別裡拿掉,複製時也只複製那個三欄位的 header(成本與資料量無關),所以日常講的「陣列」實際上都是 slice。

相關:Go 的切割上限是 cap 而不是 lenGo 傳 slice 是複製 header 而不是 pass by referenceGo 的 range 回傳 index 與 value