🍋

Goのmake関数

2024/12/15に公開

make

make関数でできることは、Slice、Map、Channel、の3つのデータ型を初期化して利用可能な状態にすること。

型Tを指定し、その後に型固有の式のリストを続ける。T型の値を返し、メモリは初期化される。

Sliceの作成

make(type, n[, m])
  • type: スライスを表す型、[]T
  • n: 長さ
  • m: 容量
s := make([]int, 3, 5)                              // int型、長さ3、容量5
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s) // len=3 cap=5 [0 0 0]

Mapの作成

make(type[, n])
  • type: Mapを表す型、map[K]V
  • n: 容量
m := make(map[string]int) // キーがstring型、値がint型
m["a"] = 10
m["b"] = 20
fmt.Println(m)            // map[a:10 b:20]

Channelの作成

make(type[, n])
  • type: Channelを表す型、chan T
  • n: バッファーサイズ
ch := make(chan int, 2) // バッファサイズ2のint型
ch <- 42
fmt.Println(<-ch)       // 42

newの話

newを使うことでもSlice等を作成することができるが、makeとは違った動きをする。

new(T)はT型のゼロ値へのポインタを返す。Slice、Map、Channelのゼロ値はnilであるため、new(T)で作成したポインタを通じて値を操作しようとするとエラーになってしまう。

nm := new(map[string]int) // newでMapの作成
fmt.Println(*nm)          // map[]
if *nm == nil {
    fmt.Println("nil!")   // nil
}

(*nm)["Apple"] = 1
出力
map[]
nil!
panic: assignment to entry in nil map(以下省略)

newで作成したMapを利用可能にするには初期化をする必要がある。
以下のコードであれば正常に動作する。

nm := new(map[string]int) // newでMapの作成
nm = &map[string]int{}

(*nm)["Apple"] = 1
fmt.Println(*nm) // map[Apple:1]

長い&ポインタ周りの変換が必要になってしまうため、基本的には makeを使うので問題ない。

参考

The Go Programming Language Specification - Built-in functions - Making slices, maps and channels
https://go.dev/ref/spec#Making_slices_maps_and_channels

Effective Go - Data - Allocation with new
https://go.dev/doc/effective_go#allocation_new

Discussion