runtime error: invalid memory address or nil pointer dereference とは
Goで「runtime error: invalid memory address or nil pointer dereference」はランタイムパニックを引き起こす深刻なエラーです。nilのポインタを間接参照(dereference)した場合に発生します。Go開発で最も頻繁に遭遇するpanicの一つです。
エラーの発生パターン
このエラーは主に以下のようなケースで発生します。
パターン1: 初期化されていないポインタの使用
type User struct {
Name string
}
func main() {
var user *User // nilポインタ
fmt.Println(user.Name) // panic: nil pointer dereference
}
ポインタ変数userは宣言のみで初期化されていないため、値はnilです。nilポインタのフィールドにアクセスするとpanicが発生します。
// 修正例1: ポインタを初期化
func main() {
user := &User{Name: "Alice"}
fmt.Println(user.Name)
}
// 修正例2: nilチェックを行う
func main() {
var user *User
if user != nil {
fmt.Println(user.Name)
}
}
パターン2: マップの未初期化
func main() {
var m map[string]int // nilマップ
m["key"] = 1 // panic: assignment to entry in nil map
}
マップはゼロ値がnilであり、nilマップへの書き込みはpanicを引き起こします。読み取りはpanicにならずゼロ値を返す点に注意してください。
// 修正: makeで初期化
func main() {
m := make(map[string]int)
m["key"] = 1
fmt.Println(m["key"]) // 1
}
パターン3: エラーハンドリングの不備
func main() {
file, err := os.Open("nonexistent.txt")
// errを無視してfileを使用
defer file.Close() // panic: nil pointer dereference
}
os.Openがエラーを返した場合、fileはnilになります。errを確認せずにfileを使用するとpanicが発生します。
// 修正: エラーを必ず確認
func main() {
file, err := os.Open("nonexistent.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// fileを安全に使用
}
根本原因の特定方法
panicが発生するとスタックトレースが出力されます。スタックトレースの最上部に表示されるファイル名と行番号を確認し、その行でポインタやインターフェースがnilになっていないかを確認します。delveデバッガを使うとブレークポイントを設定してステップ実行が可能です。
// デバッグ例
func main() {
var user *User
fmt.Printf("user: %v, is nil: %t\n", user, user == nil)
// user: <nil>, is nil: true
// nilチェック後に安全にアクセス
if user != nil {
fmt.Println(user.Name)
}
}
防止策とベストプラクティス
nil pointer dereferenceを防ぐには、ポインタやマップ、スライスを使用する前に必ず初期化を確認します。関数の戻り値でerrorが返される場合は必ずチェックし、nilの可能性がある値にはガード条件を入れましょう。
// 防止策まとめ
// 1. エラーチェックを必ず行う
result, err := someFunc()
if err != nil {
return fmt.Errorf("someFunc failed: %w", err)
}
// 2. ポインタのnilチェック
if ptr != nil {
fmt.Println(ptr.Field)
}
// 3. マップは必ずmakeで初期化
m := make(map[string]int)
// 4. コンストラクタ関数で初期化を保証
func NewUser(name string) *User {
return &User{Name: name}
}
Stack Overflowでの質問状況
Stack Overflowでは、Goに関する質問が約75,050件投稿されており、runtime error: invalid memory address or nil pointer dereferenceは最も頻繁に質問されるエラーカテゴリの一つです。
よくある質問(FAQ)
-
Qpanicとerrorの違いは何ですか?
-
A
errorはGoの通常のエラーハンドリング手段であり、関数の戻り値として返されます。panicはプログラムの実行を中断する深刻なエラーで、recover()で回復可能ですが、通常のエラー処理にはerrorを使うのがGoの慣例です。
-
Qnilマップの読み取りはpanicにならないのですか?
-
A
はい、nilマップからの読み取りはpanicにならず、値の型のゼロ値(intなら0、stringなら空文字列)を返します。ただしnilマップへの書き込みはpanicになります。この非対称性はGo初学者がつまずきやすいポイントです。
-
Qgo vetでnil pointer dereferenceを検出できますか?
-
A
go vetは一部のnil pointer dereferenceを静的に検出できますが、すべてのケースを検出することはできません。より高度な検出にはstaticcheck、nilaway(Uber製)などの外部ツールの併用が推奨されます。




コメント