· 2分で読了

makeとnewの違い

この記事は中国語から自動翻訳されたものです。翻訳によりニュアンスが失われている場合があります。

Golangには makenew という2つの予約語があり、Goを学び始めた頃に混同しやすいところでもあるので、ここに簡単なメモを残しておく。

new

newは型のメモリを割り当てて初期化するために使われ、そのメモリアドレス(ポインタ)を返す。そのため、通常はポインタ変数で new した後の型を受け取ることになる。特に注意すべき点として、newは自動的にゼロ値(zeroed value)で初期化するため、文字列なら ""、数値なら 0、channel、func、map、slice などは nil になる。

この特性があるため、mapに対して以下のような操作を行うと、panic: assignment to entry in nil map が発生する。

func main() {
	people := new(map[string]string)
	p := *people
	p["name"] = "Kalan" // panic: assignment to entry in nil map
}

初期化されたmapはnil mapになり、他のプリミティブ型のようにそのまま使えるデフォルト値を持つわけではないからだ。

struct を初期化する場合は、直接 & を使ってポインタアドレスを取得することもできる。以下の2つの書き方の効果は同じだ:

type Person struct {
  Name string
  Age  int
}

func main() {
    p := &Person{}
    p := new(Person)
}

前者の書き方のメリットは、Person に渡したい値に応じて柔軟にフィールドの初期値を設定できる点にある。一方で new はすべてのフィールドにそのままゼロ値がセットされる。

make

makenew とは異なり、channel、map、sliceなどの特定の組み込み型を初期化するために使われる。また、makeはポインタを返さない点に特に注意が必要だ。もしポインタを取得したい場合は、newのような方法を使って初期化することを検討しなければならない。

func main() {
    receiver := make(chan string) // channelを初期化するが、ポインタは返さない
    person := make(map[string]string)
    people := make([]string, 100) // 長さ100の文字列スライスを初期化
}

もう一度強調しておくが、makeはポインタを返さない! 以下のコードはエラーになる:

func main() {
	person := make(map[string]string)
	fmt.Println(*person) // invalid indirect of person
}

結論

makenew はGolangを学び始めた頃に混同しやすく、引数にポインタを渡す必要がある場面で、うっかりmakeを使って渡してしまうこともある。そのため、この2つの違いをしっかり理解しておくことが非常に重要だ。

参考文献

関連記事

他のトピックを探索