invalid memory address or nil pointer dereference の原因と直し方
値が代入されていないnilのポインタや構造体のフィールドにアクセスすると、実行時にパニックが発生します。newやリテラルで初期化する前のポインタが典型的な原因です。
エラーメッセージの読み方
panic: runtime error: invalid memory address or nil pointer dereference
panic- パニック — 実行時に回復不能な状態になったことを示します。deferとrecoverで捕まえない限り、そのままプロセスが終了します
runtime error: invalid memory address or nil pointer dereference- 詳細メッセージ — どの値が問題だったか
このエラーが出る典型パターン
パターン1
1 package main 2 3 import "fmt" 4 5 type Point struct{ X, Y int } 6 7 func main() { 8 var p *Point ^ 9 fmt.Println(p.X) 10 }
var p *Pointはnilのポインタを宣言するだけで、実体を作りません。&Point{...}でアドレスを取得する形で初期化する必要があります。
直し方: var p *Point を p := &Point{X: 1, Y: 2} にします。
パターン2
1 package main 2 3 import "fmt" 4 5 type User struct{ Name string } 6 7 func main() { 8 var p *User ^ 9 fmt.Println(p.Name) 10 }
nilのポインタが指す先のフィールドにアクセスすると、実行時にパニックが発生します。
直し方: var p *User を p := &User{Name: "go"} にします。
パターン3
1 package main 2 3 import "fmt" 4 5 type Item struct{ Price int } 6 7 func main() { 8 var p *Item ^ 9 fmt.Println(p.Price) 10 }
ポインタ変数の宣言だけでは中身が作られません。&で構造体リテラルのアドレスを取る必要があります。
直し方: var p *Item を p := &Item{Price: 500} にします。
パターン4
1 package main 2 3 import "fmt" 4 5 type Node struct{ Value int } 6 7 func main() { 8 var p *Node ^ 9 fmt.Println(p.Value) 10 }
newやリテラルで初期化する前のポインタは常にnilで、そのフィールドへのアクセスは即座にパニックします。
直し方: var p *Node を p := &Node{Value: 10} にします。
パターン5
1 package main 2 3 import "fmt" 4 5 type Box struct{ Width int } 6 7 func main() { 8 var p *Box ^ 9 fmt.Println(p.Width) 10 }
ポインタ型のゼロ値はnilです。フィールドを読む前に必ず実体を指すようにする必要があります。
直し方: var p *Box を p := &Box{Width: 30} にします。
よくある誤解
「ポインタ変数は宣言した時点で自動的に空の構造体を指しているはず」という思い込みは誤りです。初期化していないポインタの値はnilであり、その先のフィールドにアクセスすると即座にパニックします。
まとめ
invalid memory address or nil pointer dereferenceは初級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。