はじめに
Goを学び始めたばかりの頃、こんなことを思っていました。
- 「
make()
っていつ使うの?」- 「
new()
とは何が違うの?」- 「配列とスライスの違いもよくわからない…」
この記事では、Go初心者がつまずきがちな make()
の使い方と考え方を、図やコード例を交えながらまとめてみたいと思います。
🔰 make()
とは?
Goの組み込み関数 make()
は、以下の3つの内部構造を持つ型に使います。
型 | 用途 | 例 |
---|---|---|
slice |
動的配列 | make([]int, 5) |
map |
キーと値のペア | make(map[string]int) |
chan |
ゴルーチン間通信 | make(chan int) |
つまり、内部的にポインタやメモリ領域を持ち、初期化が必要な型のために使う関数です。
✅ なぜ make()
が必要なの?
たとえば map
を以下のように宣言しただけでは使えません。
var m map[string]int
m["foo"] = 1 // panic: assignment to entry in nil map
これは m
が nil
のままだからです。
正しく初期化するには make()
が必要です。
m := make(map[string]int)
m["foo"] = 1 // OK!
🧪 make()
の使い方を型別に解説
① スライス(slice)
s := make([]int, 3) // 長さ3、容量3のスライスを作る
fmt.Println(s) // [0 0 0]
s := make([]int, 2, 5) // 長さ2・容量5(内部的に余裕あり)
② マップ(map)
m := make(map[string]int)
m["a"] = 100
fmt.Println(m["a"]) // 100
m := make(map[string]int, 10) // 初期容量10(将来の挿入用)
③ チャネル(chan)
ch := make(chan int)
go func() {
ch <- 10
}()
fmt.Println(<-ch) // 10
ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch, <-ch) // 1 2
🚫 make()
を使わないケース
arr := [3]int{1, 2, 3} // 配列は make 不要
p := new(int)
*p = 100
fmt.Println(*p) // 100
🔄 make()
vs new()
比較表
make() |
new() |
|
---|---|---|
対象 | slice, map, chan | 任意の型 |
戻り値 | 値(非ポインタ) | ポインタ |
ゼロ値? | ゼロ初期化+内部構造の確保 | ゼロ初期化のみ |
用途 | 構造あり型の初期化 | ポインタが欲しいとき |
🧠 まとめ
-
make()
はスライス・マップ・チャネル専用の初期化関数 - 内部的な「領域の確保」や「ゼロ値の用意」も行ってくれる
-
new()
とは明確に用途が異なるので注意
🙋♀️ よくある初学者の疑問
Q. なぜ make([]int, 5)
と []int{}
は違うの?
A. make([]int, 5)
は要素数5のスライス([0,0,0,0,0])を作ります。
一方 []int{}
は長さ・容量0のスライスです。