new()とポインターを使う場面
newによる割り当てと一般的なポインターパターン
「new()とポインターを使う場面」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。
組み込み関数new()
new(T)はゼロ値に初期化されたTを確保し、*Tを返します。構造体の場合、&T{}と同等です:
package main
import "fmt"
func main() {
p := new(int)
fmt.Println(*p) // 0
*p = 42
fmt.Println(*p) // 42
type Point struct{ X, Y int }
pt := new(Point)
fmt.Println(*pt) // {0 0}
}newと&T{}の比較
構造体では、&T{}のほうが慣用的で、フィールドの初期化もできます。現代のGoではnewはほとんど使いません:
package main
import "fmt"
type Config struct{ Port int; Host string }
func main() {
a := new(Config) // zeroed
b := &Config{Port: 8080} // initialized
fmt.Println(a, b)
}ポインタを返す場合
次の場合はコンストラクターからポインタを返します:
- 構造体が状態を持ち、呼び出し元で同じインスタンスを共有する必要がある場合
- 構造体がポインタレシーバーのメソッドを持つ場合(インターフェースを満たすために必要です)
- 構造体が大きく、コピーのコストが高い場合
値を返す場合
次の場合は値を返します:
- 型が小さい場合(フィールドが数個の場合)
- 不変の設定である場合
- 呼び出し元が独立したコピーを受け取ることを明確にしたい場合
例: time.Timeには多くのメソッドがありますが、値として返されます。
スライスとマップ内のポインタ
コレクションにポインタを格納すると、変更を共有できます:
package main
import "fmt"
type User struct{ Name string; Score int }
func main() {
users := []*User{{"Alice", 0}, {"Bob", 0}}
users[0].Score = 100
fmt.Println(users[0]) // &{Alice 100}
}省略可能な値を表すプリミティブ型へのポインタ
*intまたは*string型のフィールドは、nilによって「未設定」を表せます。これは、omitemptyを使うJSONや、省略可能なDBカラムで役立ちます:
package main
import "fmt"
type Profile struct {
Name string
Age *int // nil means not provided
}
func main() {
p := Profile{Name: "Alice"}
fmt.Println(p.Age == nil) // true
age := 30
p.Age = &age
fmt.Println(*p.Age) // 30
}ポインタの増やし過ぎを避ける
ポインタを過度に使うとGCへの負荷が増え、キャッシュ局所性が低下します。パフォーマンスだけを理由に値型をポインタへ変更する前に、ベンチマークを実行してください。
makeとnewの比較
makeはスライス、マップ、チャネルを初期化します(これらには内部的なセットアップが必要です)。newは任意の型をゼロ値で確保し、ポインタを返します。それぞれ目的が異なります:
package main
import "fmt"
func main() {
s := make([]int, 5) // usable slice
m := make(map[string]int) // usable map
p := new(int) // *int pointing to 0
fmt.Println(s, m, *p)
}不変ポインタパターン
*Tを返しますが、不変であることをドキュメントに記載します。利用側では変更しないでください。これは、複数のゴルーチンで共有する設定オブジェクトでよく使われます。
ポインタの安全性に関するまとめ
ポインタを安全に扱うためのルール:
- デリファレンスする前に必ずnilを確認します
- スタック変数へのポインタを、その変数の有効期間を超えて保持しないでください(Goのエスケープ解析がこれを処理します)
- 絶対に必要な場合を除き、unsafe.Pointerをキャストしないでください
- スタックとヒープのどちらを使うかはコンパイラーに任せてください
確認問題
new(int)は何を返しますか?
まとめ: newとポインタ
重要なポイント:
new(T)はゼロ値の*Tを返します。ほとんど使わないため、&T{}を優先します- 小さい型や不変の型では値を、状態を持つ型や大きな型ではポインタを返します
*T型のフィールドによって、nilで「存在しない」ことを表せます- ポインタを使い過ぎないでください。GCにはコストがかかります
練習課題
MaxConnections用の*intフィールドを持つSettings構造体を作成してください。*Settingsを受け取り、フィールドがnilの場合にだけデフォルト値を設定する関数を作成してください。
よくある質問
「new()とポインターを使う場面」レッスンは無料ですか?
はい。「new()とポインターを使う場面」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。
「new()とポインターを使う場面」で何を学びますか?
newによる割り当てと一般的なポインターパターン ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Go Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「new()とポインターを使う場面」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGo Academyレッスンでコードを書いて実行できますか?
はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- ポインターとは
- ポインターと関数
- メソッドのポインターレシーバー
- new()とポインターを使う場面