Slice 的四種建立方式與 nil
選哪一種取決於兩件事:內容知不知道、之後要用 index 指派還是用 append。
// 一、已知內容:直接用字面量
people := []string{"Aaron", "Jim", "Bob", "Ken"}
// 二、make 給 len:開好位置填 zero value,之後用 index 指派
scores := make([]int, 4) // len=4 cap=4 [0 0 0 0]
// 三、只宣告不配置:搭配 append
var names []string // len=0 cap=0 nil
// 四、make 給 len=0 加 cap:大概知道要幾個,搭配 append
buf := make([]string, 0, 5) // len=0 cap=5 []make 的三種給法
make([]T, len, cap) 的第三個參數可省略,省略時 cap 等於 len:
| 寫法 | len | cap | 之後怎麼填 |
|---|---|---|---|
make([]int, 4) | 4 | 4 | s[i] = x(位置已存在) |
make([]int, 0, 5) | 0 | 5 | s = append(s, x)(不會觸發擴容) |
make([]int, 4, 10) | 4 | 10 | 前 4 個用 index,之後 append |
選錯的後果是實際的:make([]int, 0, 10) 之後寫 s[7] = 9 會 panic(len 不夠),而 make([]int, 10) 之後 append 會從第 11 個開始接,前面多出 10 個 0。
nil 是 slice 的 zero value
var s []int 得到的 slice 是 nil:len 與 cap 都是 0,而且沒有底層 array(連空的都沒有)。
var s []int
fmt.Println(len(s), cap(s), s == nil) // 0 0 true
s = append(s, 1) // 可以直接 append,會替它配置實用上 nil slice 幾乎等同空 slice:len()、range、append 都能直接用,不需要先初始化。差別只在 s == nil 的判斷,以及序列化成 JSON 時 nil 變 null、空 slice 變 []。