Go で「invalid memory address or nil pointer dereference」が解決できない
Go の `runtime error: invalid memory address or nil pointer dereference` は、nil のポインタやインタフェースに対してフィールドアクセス・メソッド呼び出しを行ったときに発生します。
代入直前に nil チェックを入れ、関数の戻り値で error を先に確認するのが基本対処です。
#nil#pointer#panic#runtime-error
公開:
要約
panic: runtime error: invalid memory address or nil pointer dereference は、Go のポインタが nil のままフィールドアクセスやメソッド呼び出しをしたときに発生します。
多くは関数の戻り値で error を確認せずに使っているか、interface に nil のポインタを入れて != nil 判定が誤動作しているのが原因です。
使用直前で nil チェックを入れ、戻り値の規約を統一すれば大半は防げます。
よくある原因
- 初期化していない
var p *Tをそのまま使っている func New() (*T, error)の戻り値で error を見ずに*Tを呼び出している- interface 値(例:
var e error)に nil のポインタを代入しており、if e != nilが true になりながら中身は nil map[string]*Fooで未登録キーを引いて nil が返ったのに気付かず参照している
解決策
1. 使用直前で nil チェックする
func process(u *User) error {
if u == nil {
return fmt.Errorf("user is nil")
}
fmt.Println(u.Name)
return nil
}2. error を先に確認する
u, err := repo.FindByID(id)
if err != nil {
return err
}
fmt.Println(u.Name)戻り値の規約として「error が nil の時はポインタも非 nil」を徹底すると、毎回の nil チェックが不要になります。
3. nil interface の罠を避ける
type MyErr struct{}
func (*MyErr) Error() string { return "my error" }
func mayFail(cond bool) error {
var e *MyErr
if cond {
e = &MyErr{}
}
return e // ← 型付き nil が interface にラップされ、!= nil が true になる
}戻り値型が error の関数では失敗時のみ非 nil のポインタを返すように分岐を明示します(公式 FAQ)。
func mayFail(cond bool) error {
if cond {
return &MyErr{}
}
return nil // 明示的に untyped nil を返す
}4. map アクセスは存在確認を付ける
if v, ok := users[id]; ok {
fmt.Println(v.Name)
} else {
return fmt.Errorf("user %s not found", id)
}ポインタ値が入る map では、未登録キーで返るゼロ値 (nil) を二項代入で必ず捕捉してから参照します。