Goの関数makeは、slice、map、およびchannelの型のオブジェクトを初期化するためにのみ使用されます。必要なデータ構造を確保し、動作可能なオブジェクト(ポインタではなく)を返します。
例:
s := make([]int, 5, 10) // 長さ5、容量10のスライス m := make(map[string]int) // 空のマップ ch := make(chan int, 2) // サイズ2のバッファ付きチャネル
細かい点:
sliceのパラメータは、長さ(len)と(オプションの)容量(cap)です。mapおよびchanには、(オプションの)容量(初期サイズ/バッファ)のみがあります。makeは、すでに初期化されたオブジェクトを返し、使用する準備が整っています。makeは使用せず、リテラルやnewを使用して初期化します(これはゼロ値へのポインタを返します)。newとの比較:
new(T)は、すべてのフィールドがゼロの*Tを返します。make(T)は、slice、map、chanの3つの型に対してのみTを返します。makeの代わりにnewを使って動作するmapを取得することはできますか?
m := new(map[string]int) (*m)["a"] = 1 // 何が起こるでしょうか?
多くの人は、これが正しいと思っていますが、ランタイムでpanicが発生します:assignment to entry in nil map。なぜなら、変数*mにはnilが入っているからです!
正しく使用する: makeを使用します:
m := make(map[string]int) m["a"] = 1 // OK
逸話
マイクロサービスでキャッシュを保存するために、var cache map[string]interface{}のようにmakeで初期化せずにマップを作成したところ、書き込み時にプロダクションでpanicが発生し、わけのわからないスタックトレースが表示されました。問題はコードの分析を経てのみ発見されました:マップはnilでした。
逸話
データパイプラインを作成する際、チャネルのバッファを忘れ、make(chan int)を使用しました。その結果、ゴルーチンは読み込みを待ってつまずき、非同期交換が期待されていたのに対して同期的になってしまいました。このエラーは、大規模テストでのみ発見されました。
逸話
あるプロジェクトでは、初期化がnewを通じて行われていましたが、一部の開発者がmake([]int, 10)の代わりにnew([]int)を使用しようとして、最終的にnilスライスへのポインタを取得し、最初の書き込みでランタイムpanicが発生しました。