json.Unmarshalで非公開(小文字始まり)フィールドが無視される
encoding/jsonパッケージは、構造体の小文字始まりの非公開フィールドを読み書きできません。JSONのキーに対応するフィールド名を小文字で書いてしまうと、値が入らないままゼロ値になります。
なぜエラーが出ないのか
出力: {name:}
(エラーなし)- Goは何も報告しません。コンパイルも実行も正常に終わるコードだからです
出力: {name:}- 実際の出力 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 ) 7 8 type User struct { 9 name string ^ 10 } 11 12 func main() { 13 var u User 14 json.Unmarshal([]byte(`{"name":"go"}`), &u) 15 fmt.Printf("%+v\n", u) 16 }
出力: {name:}JSONは{"name":"go"}
小文字始まりのnameフィールドはencoding/jsonからアクセスできず、値が設定されないまま空文字列で残ります。
直し方: name を Name にします。
広告
広告スロット(未設定)
パターン2
1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 ) 7 8 type Account struct { 9 age int ^ 10 } 11 12 func main() { 13 var a Account 14 json.Unmarshal([]byte(`{"age":30}`), &a) 15 fmt.Printf("%+v\n", a) 16 }
出力: {age:0}JSONは{"age":30}
数値フィールドでも同様で、非公開フィールドにはリフレクション経由で値を書き込めずゼロ値の0のまま残ります。
直し方: age を Age にします。
パターン3
1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 ) 7 8 type Contact struct { 9 email string ^ 10 } 11 12 func main() { 13 var c Contact 14 json.Unmarshal([]byte(`{"email":"go@example.com"}`), &c) 15 fmt.Printf("%+v\n", c) 16 }
出力: {email:}JSONは{"email":"go@example.com"}
JSONのキーとフィールド名の文字列としての一致だけでは不十分で、Go側は公開フィールドである必要があります。
直し方: email を Email にします。
パターン4
1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 ) 7 8 type Flag struct { 9 active bool ^ 10 } 11 12 func main() { 13 var f Flag 14 json.Unmarshal([]byte(`{"active":true}`), &f) 15 fmt.Printf("%+v\n", f) 16 }
出力: {active:false}JSONは{"active":true}
bool型でもゼロ値であるfalseのまま残るため、パースが成功したのか失敗したのか気づきにくいバグになります。
直し方: active を Active にします。
パターン5
1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 ) 7 8 type Product struct { 9 price float64 ^ 10 } 11 12 func main() { 13 var p Product 14 json.Unmarshal([]byte(`{"price":9.99}`), &p) 15 fmt.Printf("%+v\n", p) 16 }
出力: {price:0}JSONは{"price":9.99}
フィールド名を大文字始まりに変更するだけで、JSONのキーとは大文字小文字の違いがあっても自動的にマッチします。
直し方: price を Price にします。
よくある誤解
「フィールド名がJSONのキーと文字列として一致していれば、大文字小文字に関わらず値が入るはず」という思い込みは誤りです。encoding/jsonはリフレクションを使うため、パッケージ外からもアクセスできる大文字始まりの公開フィールドでなければ値を設定できません。
まとめ
json.Unmarshalで非公開(小文字始まり)フィールドが無視されるは中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。