makeとnewの違い
Golangには make と new という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
make は new とは異なり、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
}
結論
make と new はGolangを学び始めた頃に混同しやすく、引数にポインタを渡す必要がある場面で、うっかりmakeを使って渡してしまうこともある。そのため、この2つの違いをしっかり理解しておくことが非常に重要だ。
参考文献
関連記事
- 測定が目標になるとき:窓税からPull Request数まで かつて僕は小さなツールを自作し、四半期で自分がどれだけPRに貢献したか、レビューコメントをどれだけ残したか、チケットをどれだけ消化したかを集計して、上司にアウトプットを証明しようとしたことがある。上司は淡々と、評価はアウトプットだけで見るものではないと言った。数年後、僕はようやく理解した――測定が目標になるとき、それはもはや良い測定ではなくなるのだ。英国の窓税、ハノイのネズミ駆除の報奨金から、現代のPR数による開発者評価に至るまで、そのメカニズムはまったく同じだ。
- Cloudflare Images を画像ストレージ・変換ソリューションとして使う ウェブページに画像を1枚置くのはフロントエンドにとって最も簡単なことだが、リサイズや各種フォーマットの生成、さらにはトラフィックの負荷に耐えることまで完璧にやろうとすると、実際には一つの包括的なソリューションが必要になる。僕はその後、すべて Cloudflare Images に任せるようになり、オリジナル画像1枚だけを渡すようにしている。
- もう AWS Access Key を使うのはやめよう Access Key は AWS において見落とされがちなセキュリティリスクだ。OIDC と IAM Role を組み合わせることで、GitHub Actions にシークレットを一切保持させることなく、安全に AWS リソースを操作できるようにする。
- データベース主キー:AUTO_INCREMENT、UUID、そしてUUIDv7 バックエンド開発で度々直面する主キーの決定。auto incrementを使うべきか、それともUUIDか?衝突への懸念は?UUIDv7とcreated_at + インデックスの性能差はどれほどか?実際に2,000万件のデータで検証したベンチマークと設計上の意思決定を解説する。