Go 資料與記憶體分配 (Data)
整理自 Effective Go - Data,涵蓋 new / make、複合字面量、陣列 / 切片 / 映射 與 append。
1. 分配:new 與 make
| 函數 | 用途 | 回傳型別 | 適用類型 |
|---|---|---|---|
new(T) | 分配已置零的記憶體 | *T(指標) | 任意型別 |
make(T, args) | 初始化內部結構 | T(值,非指標) | 僅 slice、map、channel |
new(T)
- 只做「置零」,不呼叫建構函式;回傳的是指向零值的指標。
- 設計資料結構時,可善用「零值即可用」:例如
bytes.Buffer、sync.Mutex的零值都可直接使用。
p := new(SyncedBuffer) // type *SyncedBuffer
var v SyncedBuffer // 零值,可直接使用
make(T, args)
- slice、map、channel 底層是引用型別,必須先初始化(例如切片的 pointer、len、cap)才能用,因此用
make。 new([]int)得到的是「指向 nil slice 的指標」,實務上幾乎用make([]int, len, cap)。
// 不建議
var p *[]int = new([]int) // *p == nil
*p = make([]int, 100, 100)
// 建議
v := make([]int, 100)
2. 建構函式與複合字面量 (Composite Literals)
- 零值不夠用時,可用複合字面量建立並初始化實例。
- 回傳局部變數的位址在 Go 是安全的(編譯器會做逃逸分析)。
// 依欄位順序
f := &File{fd, name, nil, 0}
// 欄位: 值,順序可打散,未給的為零值
f := &File{fd: fd, name: name}
// 無欄位 = 零值,等價於 new(File)
&File{}
複合字面量也可用於 array、slice、map(標籤為索引或鍵):
a := [...]string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"}
s := []string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"}
m := map[int]string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"}
3. 陣列 (Arrays)
陣列是長度固定且索引連續的資料結構。與 C 的差異:
- 陣列是值:賦值會複製整個陣列;傳入函數也是複本,不是指標。
- 長度是型別的一部分:
[10]int與[20]int是不同型別。