Goにおけるmakeとnewの選択
Daniel Hayes
Full-Stack Engineer · Leapcell

Go言語は、make
とnew
という2つの一般的なメモリ割り当て方法を提供しています。どちらもメモリ割り当てに使用されますが、その役割と使用場面は大きく異なります。これら2つの違いを理解することは、効率的で保守性の高いGoコードを書く上で非常に重要です。この記事では、make
とnew
の違い、適切なシナリオ、およびいくつかの使用上のヒントについて徹底的に分析します。
make
とnew
の基本的な違い
new: ポインタ型のゼロ値を生成
new
は、Goにおけるメモリ割り当てに使用されるキーワードです。その機能は、型のためのメモリブロックを割り当て、そのメモリへのポインタを返すことです。new
によって割り当てられたメモリは、その型のゼロ値に初期化されます。
例: new
の使用
package main import "fmt" func main() { var p *int = new(int) fmt.Println(*p) // 出力: 0, `new`によってint用に割り当てられたメモリはゼロ値に初期化される }
- 戻り値の型:
new
は型へのポインタを返します。 - ゼロ値初期化:
new
は割り当てられたメモリをその型のゼロ値に初期化します。たとえば、int
型の場合、ゼロ値は0
、string
型の場合、空文字列""
です。
make: スライス、マップ、チャネルを初期化
make
は、Goの特別な組み込み関数であり、特にスライス、マップ、チャネルの3つの組み込みデータ型を初期化するために使用されます。new
とは異なり、make
は割り当てられたメモリへのポインタを返さず、初期化されたオブジェクト自体を返します。
例: make
の使用
package main import "fmt" func main() { // スライスの初期化 s := make([]int, 5) fmt.Println(s) // 出力: [0 0 0 0 0] // マップの初期化 m := make(map[string]int) m["age"] = 30 fmt.Println(m) // 出力: map[age:30] // チャネルの初期化 ch := make(chan int, 2) ch <- 1 fmt.Println(<-ch) // 出力: 1 }
- 戻り値の型:
make
はポインタではなく、オブジェクト自体(スライス、マップ、またはチャネル)を返します。 - メモリ割り当てと初期化:
make
はメモリを割り当てるだけでなく、データ構造自体も初期化します。たとえば、スライスを初期化する場合、make
は基になる配列を割り当て、その長さと容量を設定します。
主な違いのまとめ
-
目的:
new
: メモリを割り当て、型へのポインタを返します。make
: スライス、マップ、またはチャネルオブジェクトを初期化して返します。
-
戻り値:
new
: 型へのポインタを返します。make
: 初期化されたオブジェクト自体を返します。
-
適用可能な型:
new
: すべての型。make
: スライス、マップ、チャネル。
-
初期化:
new
: ゼロ値を返します。make
: データ構造の型に応じて初期化します。
make
とnew
の使用上のヒント
new
の使用上のヒント
構造体型に適しています:
new
は、構造体のメモリを割り当て、それへのポインタを返すためによく使用されます。構造体ポインタの初期値は、構造体のゼロ値であることに注意することが重要です。
例: new
を使用して構造体のメモリを割り当てる
type Person struct { Name string Age int } func main() { p := new(Person) fmt.Println(p) // 出力: &{ 0} fmt.Println(p.Name) // 出力: 空文字列 fmt.Println(p.Age) // 出力: 0 }
new
によって作成されたポインタ:new
は構造体へのポインタを返すため、p.Name
またはp.Age
でそのフィールドを直接変更できます。
make
の使用上のヒント
指定された容量でスライスを初期化する:
make
を使用して、指定された長さと容量でスライスを初期化できます。make
を使用すると、基になる配列を効率的に割り当ててスライスを初期化できます。
例: make
を使用して容量を持つスライスを初期化する
// 長さ5、容量10のスライスを初期化 s := make([]int, 5, 10) fmt.Println(len(s), cap(s)) // 出力: 5 10
- 初期化中にマップの容量を指定する:
make
でマップを作成するときに、その初期容量を指定できます。これにより、要素が挿入される際の複数のメモリ拡張を回避することでパフォーマンスを最適化できます。
例: make
を使用してマップを初期化する
m := make(map[string]int, 10) // 初期容量を10に設定 m["age"] = 30 m["height"] = 175 fmt.Println(m) // 出力: map[age:30 height:175]
- バッファ付きチャネルを初期化する:
make
を使用してバッファ付きチャネルを作成し、チャネルのバッファサイズを指定します。これは同時実行プログラミングで非常に役立ちます。
例: make
を使用してバッファ付きチャネルを作成する
ch := make(chan int, 2) ch <- 1 ch <- 2 fmt.Println(<-ch) // 出力: 1
適切なメモリ割り当て方法の選択
- 構造体の使用シナリオ: 構造体へのポインタのみが必要で、初期化中に特別な要件がない場合は、
new
を使用するのが簡単で一般的なアプローチです。 - スライス、マップ、チャネルの使用シナリオ: スライス、マップ、チャネルを初期化する必要があり、その内容を変更する可能性がある場合は、
make
がより適切な選択です。特に、事前に容量を指定する必要がある場合はそうです。
make
とnew
のパフォーマンスに関する考慮事項
- メモリ割り当てのオーバーヘッド: スライス、マップ、チャネルを初期化する場合、
make
はメモリを割り当てるだけでなく、型の初期化も実行するため、追加のオーバーヘッドが発生する可能性があります。対照的に、new
はメモリを割り当てるだけでゼロ値に初期化するため、そのオーバーヘッドは比較的小さくなります。 - 不要なメモリ割り当ての回避: スライス、マップ、チャネルなどの型の場合、
make
を使用するときに適切な容量を指定して、メモリの再割り当て回数を減らすことをお勧めします。
よくある誤用
- スライスまたはマップを作成するために
new
を誤って使用する:new
がスライス、マップ、またはチャネルで使用される場合、その型のゼロ値のみを返し、初期化は実行しません。したがって、new
を使用してスライス、マップ、またはチャネルを作成し、その内容に直接アクセスしようとすると、ランタイムエラーが発生します。
不正な例: new
を誤って使用してマップを作成する
m := new(map[string]int) // 不正: ポインタを返し、初期化されたマップは返さない m["age"] = 30 // ランタイムエラー: mはnilです
正しい例: make
を使用してマップを初期化する必要があります。
m := make(map[string]int) m["age"] = 30
まとめ
Goでは、make
とnew
はどちらもメモリ割り当てのためのキーワードであり、その機能は似ていますが、明確な違いがあります。
new
は型のメモリを割り当てるために使用され、ポインタを返し、ほとんどの型に適しています。
一方、make
は主にスライス、マップ、チャネルを初期化するために使用され、より強力な初期化機能を提供します。
new
: 構造体型やその他の基本型へのポインタの作成に適しており、メモリをゼロ値に初期化します。make
: スライス、マップ、チャネルの初期化に使用され、容量の指定をサポートし、内部初期化を完了します。
これら2つの異なる使用シナリオとパフォーマンスへの影響を理解することは、より効率的で保守性の高いGoコードを作成するのに役立ちます。
Leapcellは、Goプロジェクトをホストするための最適な選択肢です。
Leapcellは、Webホスティング、非同期タスク、およびRedisのための次世代サーバーレスプラットフォームです。
多言語サポート
- Node.js、Python、Go、またはRustで開発します。
無制限のプロジェクトを無料でデプロイ
- 使用量に対してのみ支払い - リクエストも料金もかかりません。
圧倒的なコスト効率
- アイドル料金なしの従量課金制。
- 例:25ドルで、平均応答時間60ミリ秒で694万リクエストをサポートします。
合理化された開発者エクスペリエンス
- 簡単なセットアップのための直感的なUI。
- 完全に自動化されたCI/CDパイプラインとGitOps統合。
- 実用的な洞察のためのリアルタイムのメトリックとログ。
簡単なスケーラビリティと高いパフォーマンス
- 高い同時実行性を簡単に処理するための自動スケーリング。
- 運用オーバーヘッドゼロ - 構築に集中するだけです。
ドキュメントで詳細をご覧ください!
Xでフォローしてください:@LeapcellHQ