Code Fix

初級

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  }
panic: runtime error: invalid memory address or nil pointer dereference

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  }
panic: runtime error: invalid memory address or nil pointer dereference

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  }
panic: runtime error: invalid memory address or nil pointer dereference

ポインタ変数の宣言だけでは中身が作られません。&で構造体リテラルのアドレスを取る必要があります。

直し方: 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  }
panic: runtime error: invalid memory address or nil pointer dereference

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  }
panic: runtime error: invalid memory address or nil pointer dereference

ポインタ型のゼロ値はnilです。フィールドを読む前に必ず実体を指すようにする必要があります。

直し方: var p *Box を p := &Box{Width: 30} にします。

この問題を解いてみる →

よくある誤解

「ポインタ変数は宣言した時点で自動的に空の構造体を指しているはず」という思い込みは誤りです。初期化していないポインタの値はnilであり、その先のフィールドにアクセスすると即座にパニックします。

実務での勘所

Goには「あらゆる型にゼロ値があり、そのゼロ値は安全に使えるべきだ」という設計哲学があります。数値のゼロ値0、文字列のゼロ値""、真偽値のゼロ値falseは、いずれも初期化しなくてもそのまま安全に使える値です。しかしポインタのゼロ値nilだけはこの理想から外れており、そのまま参照(デリファレンス)すると即座にパニックします。ポインタを扱う際は「宣言しただけでは実体を指していない」ことを常に意識する必要がある、数少ない例外的な領域です。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)