interface conversion panic の原因と直し方
型アサーション v.(T) は、vの実際の型がTでない場合に実行時パニックを起こします。2つ目の戻り値(ok)を受け取らずに単一戻り値の形で書くと、失敗時にそのままパニックします。
エラーメッセージの読み方
panic: interface conversion: interface {} is string, not int
panic- パニック — 実行時に回復不能な状態になったことを示します。deferとrecoverで捕まえない限り、そのままプロセスが終了します
interface conversion: interface {} is string, not int- 詳細メッセージ — どの値が問題だったか
このエラーが出る典型パターン
パターン1
1 package main 2 3 import "fmt" 4 5 func main() { 6 var i interface{} = "hello" ^ 7 n := i.(int) 8 fmt.Println(n) 9 }
panic: interface conversion: interface {} is string, not intiの実際の型はstring
単一戻り値の形の型アサーションi.(int)は、iの実際の型がintでなければその場でパニックします。
直し方: "hello" を 42 にします。
広告
広告スロット(未設定)
パターン2
1 package main 2 3 import "fmt" 4 5 func main() { 6 var i interface{} = true ^ 7 n := i.(int) 8 fmt.Println(n) 9 }
panic: interface conversion: interface {} is bool, not intiの実際の型はbool
boolを格納したinterfaceに対してintへの型アサーションを行うと、実際の型がbool, not intとしてパニックします。
直し方: true を 42 にします。
パターン3
1 package main 2 3 import "fmt" 4 5 func main() { 6 var i interface{} = 3.14 ^ 7 n := i.(int) 8 fmt.Println(n) 9 }
panic: interface conversion: interface {} is float64, not intiの実際の型はfloat64
数値同士に見えてもfloat64とintは別の型で、暗黙の変換はされず型アサーションは失敗します。
直し方: 3.14 を 42 にします。
パターン4
1 package main 2 3 import "fmt" 4 5 func main() { 6 var i interface{} = []int{1, 2} ^ 7 n := i.(int) 8 fmt.Println(n) 9 }
panic: interface conversion: interface {} is []int, not intiの実際の型は[]int
スライスをintに変換しようとするような明らかな型違いでも、コンパイルは通ってしまい実行時に発覚します。
直し方: []int{1, 2} を 42 にします。
パターン5
1 package main 2 3 import "fmt" 4 5 func main() { 6 var i interface{} = int64(5) ^ 7 n := i.(int) 8 fmt.Println(n) 9 }
panic: interface conversion: interface {} is int64, not intiの実際の型はint64
int64とintは同じ「整数」でもGoでは別の型として区別され、型アサーションはint64, not intとして失敗します。
直し方: int64(5) を 42 にします。
よくある誤解
「型が違っていても、アサーションはゼロ値を返してくれるはず」という思い込みは誤りです。単一戻り値の形の型アサーションは失敗時にパニックするため、失敗しうる場合はv, ok := v.(T)の形でokを確認する必要があります。
まとめ
interface conversion panicは中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。