5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Go言語】newとmakeの違いについて解説

Posted at

はじめに

今回、Go言語のnew関数とmake関数の違いについて解説していこうと思います。
この2つの関数は似ているので、初学者の方には混乱を招くことがあります。
本記事で、2つの特徴を掴み理解を深めていきましょう。

まずは、それぞれの関数の解説から始めます。

new関数 について

  • new関数
    • 指定された型の新しいインスタンスをメモリ上に割り当て、そのポインタを返す関数
    • new関数によって割り当てられた値は、その型のゼロ値で初期化されます

実際にnew関数は以下のように使用できます。

main.go
package main

import "fmt"

func main() {
	var p *int = new(int)
	fmt.Println(p) //出力:0x1400000e0a8
}

アドレスが確保されていることが確認できたかと思われます。
では、new関数を使わない場合も考えてみましょう。

main.go
package main

import "fmt"

func main() {
	var p *int = new(int)
	fmt.Println(p) //出力:0x1400000e0a8

// p2というポインタ型を宣言
	var p2 *int
	fmt.Println(p2) //出力: <nil>
}

The Go Playground:実行してみましょう。

上記のことから以下の点がわかります。

  • new関数はメモリ領域を確保してくれるため、アドレスが返ってくる
  • 変数p2はメモリを確保していないためnil値が出力された

変数pにはデフォルトで「0」が入っています。

main.go
func main() {
	var p *int = new(int)
	fmt.Println(*p)
 // 1インクリメントしてみる
	*p++
	fmt.Println(*p)
}

The Go Playground:実行してみましょう。
実行してみると、デフォルト値「0」に+1され「1」が返ってきてますね。

こちらの操作を先ほどの変数p2にも行ってみましょう。

main.go
var p2 *int
	*p2++
	fmt.Println(*p2)

The Go Playground:実行してみましょう。
こちら実行すると「panic」が発生します。
エラー内容を見てみると以下のように書いてあります。

invalid memory address or nil pointer dereference

まだメモリに値が確保されていないので、その中身にアクセスしようとしたためpanicになったことが確認できます。

  • new関数と普通の宣言は異なることなので区別しておきましょう!
  • 構造体の場合はnew関数を使うよりも、構造体リテラルを使用してインスタンスを直接初期化する方が一般的です

続いて、make関数について解説していきます。

make関数 について

  • slice, map, channelといったビルトインの参照型のために使用されます
  • 新しいインスタンスを作成し、その初期化を行います

実際にコードを書いていきましょう。

sliceの初期化

  • make関数を使ってスライスを初期化する際には、スライスの型、長さ、容量を指定する必要があります
  • 容量については省略することができますが、その場合は容量には長さと同じ値が設定されます
//長さ10, 容量15のスライスを作成
s := make([]int, 10, 15)

mapの初期化

  • マップを初期化する際はmake関数にキーとバリューの型を渡す必要があります
// キーがstring型、バリューがint型のmapを作成
m := make(map[string]int)

channelの初期化

  • チャネルは、ゴルーチン間でのデータの受け渡しに使用されます
  • チャネルの初期化はチャネルの型とバッファサイズを指定することができます
  • バッファサイズを指定しない場合は非バッファチャネルが作成されます
// int型のバッファサイズ5のchannelを作成
ch := make(chan int, 5) 

new関数とmake関数の違い

まずは以下のコードを見てみましょう。

main.go
package main

import (
	"fmt"
)

func main() {
	// スライスを作成し、その型を表示
	s := make([]int, 0)
	fmt.Printf("%T\n", s)

	// マップを作成し、その型を表示
	m := make(map[string]int)
	fmt.Printf("%T\n", m)

	// チャネルを作成し、その型を表示
	ch := make(chan int)
	fmt.Printf("%T\n", ch)

	// new関数を使ってゼロ値で初期化されたインスタンスのポインタを返却
	var st = new(int)
	fmt.Printf("%T\n", st)

	// ポインタを作成し、その型を表示
	var p *int = new(int)
	fmt.Printf("%T\n", p)
}

The Go Playground:実行してみましょう。

実行してみると structと変数 p だけが、ポインタ型で返ってきていることがわかるかと思います。

つまり、
「ポインタが返ってくる返り値のものにはnew関数を使い、そうでない場合はmakeを使います」

より詳細に説明すると、以下のように言えます。

  • make関数:初期化済みのインスタンスを直接返却
  • new関数:ゼロ値で初期化された指定された型の新しいインスタンスのポインタを返却

さいごに

本記事では、Go言語のnew関数make関数の違いについて詳しく解説しました。これらの関数の特徴や使用方法を正しく理解することで、より効果的なコードを書いていきましょう!

参考

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?