JSONライブラリにGoの構造体を投げ入れるとき、
- 構造体のエイリアスやフィールド名を大文字にしたらいいんだっけ、小文字にしたらいいんだっけ、
- jsonタグとフィールド名のどっちが優先的にマッピングの対象になるんだっけ、
と悩んだので、いろいろ実験してみました。
普通(?)
投げ入れるjsonのプロパティ名と受け取る構造体のフィールド名が完全に一致している場合は当然、期待通りマッピングできる
package main
import (
"encoding/json"
"fmt"
"log"
)
type User struct {
Id int
Name string
}
func main() {
src := `{"Id":3,"Name":"nao"}`
u := new(User)
err := json.Unmarshal([]byte(src), u)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", u)
}
// 出力結果:&{Id:3 Name:nao}
jsonのkey値が小文字の場合
投げ入れるjsonのプロパティ名が小文字で受け取る構造体のフィールド名が大文字のときどうなるんでしょう。
頭文字の大小が違ってもマッピングできてますね!
package main
import (
"encoding/json"
"fmt"
"log"
)
type User struct {
Id int
Name string
}
func main() {
src := `{"id":3,"name":"nao"}`
u := new(User)
err := json.Unmarshal([]byte(src), u)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", u)
}
// 出力結果:&{Id:3 Name:nao}
構造体フィールド名小文字にした場合
jsonのプロパティ名も小文字、構造体のフィールド名も小文字の場合はどうでしょう。
マッピングできてませんね。
フィールド名が小文字だとプライベートなフィールドとして認識されてしまいます。Userという構造体のフィールドid, nameはpackage mainの中でしか触ることができません。
package jsonに構造体のフィールドを渡すにはフィールド名を大文字始まりにしないといけません。
Goの基本文法ですが忘れてるとハマりがちですね。
package main
import (
"encoding/json"
"fmt"
"log"
)
type User struct {
id int
name string
}
func main() {
src := `{"id":3,"name":"nao"}`
u := new(User)
err := json.Unmarshal([]byte(src), u)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", u)
}
// 出力結果:&{id:0 name:}
構造体フィールド名とJSONキー名が不一致+jsonタグをつける
投げ入れられるjson名をそのままGoの世界で扱いたくないということはよくあります。
e.g. json名をGoの世界でそのまま使いたくないとき
- プロジェクトの命名規則と異なる。
- すでにnameという変数は使われていて名前がバッティングする。
- nameってなんの名前のこと指してるのかわからない。わかりやすいフィールド名にしたい。
そんなときはjsonタグをつけてやるとよいです。
投げ入れられるjsonのプロパティ名とjsonタグが一致していれば、構造体のフィールド名は好きに設定できます
package main
import (
"encoding/json"
"fmt"
"log"
)
type User struct {
UserId int `json:"id"`
UserName string `json:"name"`
}
func main() {
src := `{"id":3,"name":"nao"}`
u := new(User)
err := json.Unmarshal([]byte(src), u)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", u)
}
// 出力結果:&{UserId:3 UserName:nao}
構造体名を小文字
フィールド名は大文字始まりじゃないといけないみたいですが、構造体名自体は小文字始まりでよいみたいです。。。
import (
"encoding/json"
"fmt"
"log"
)
type user struct {
UserId int `json:"id"`
UserName string `json:"name"`
}
func main() {
src := `{"id":3,"name":"nao"}`
u := new(user)
err := json.Unmarshal([]byte(src), u)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", u)
}
// 出力結果:&{UserId:3 UserName:nao}
jsonタグ名とJSONキー名の大文字小文字は適当でいい
わざわざそんなことする必要もないですが。。。
import (
"encoding/json"
"fmt"
"log"
)
type user struct {
UserId int `json:"Id"`
UserName string `json:"nAme"`
}
func main() {
src := `{"id":3,"NamE":"nao"}`
u := new(user)
err := json.Unmarshal([]byte(src), u)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", u)
}
// 出力結果:&{UserId:3 UserName:nao}
そもそも構造体のエイリアスを設定する必要はない
手軽にJSONからデータを取り出したいなら
package main
import (
"encoding/json"
"fmt"
"log"
)
func main() {
src := `{"id":3,"name":"nao"}`
u := &struct{UserName string `json:"name"`}{}
err := json.Unmarshal([]byte(src), u)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", u)
}
// 出力結果:&{UserName:nao}