json【Go】
JSON形式から変数に、変数からJSON形式に変換する方法を見ていきます。
JSONから変数
まずは、JSON形式から変数への変換です。
type Person struct { // 各フィールド名の頭文字は、必ず大文字にする Name string Age int Nicknames []string } func main() { var p Person b := []byte(`{"name":"mike","age":19,"nicknames":["mike","mic","micky"]}`) // json形式のbyte配列を生成 if err := json.Unmarshal(b, &p); err != nil { // 値を変更するため、変数はポインタで渡す fmt.Println(err) } fmt.Println(p.Name, p.Age, p.Nicknames) // mike 19 [mike mic micky] }
Unmarshalする際の格納先の型については注意が必要です。structの中のフィールドは頭文字を大文字にしないと、格納することができません。
Unmarshal先のstructのフィールドは、必ず頭文字を大文字にします。
変数からJSON
続いて、変数からJSON形式への変換です。
type Person struct { Name string Age int Nicknames []string } func main() { var p Person b := []byte(`{"name":"mike","age":19,"nicknames":["mike","mic","micky"]}`) // json形式のbyte配列を生成 if err := json.Unmarshal(b, &p); err != nil { // 変数はポインタで渡す fmt.Println(err) } v, _ := json.Marshal(p) // 使用しないため、errは破棄 fmt.Println(string(v)) // byte配列をstringにcast {"Name":"mike","Age":19,"Nicknames":["mike","mic","micky"]} }
デフォルトのままですと、json.Marshal(v interface{})が返す値のフィールド名、型は、
変換対象である変数の定義に沿ったものになります。json出力時の定義を変更したいという場合、
下記の通り、変数の定義を「jsonの時はこうして欲しい」というように記述することができます。
type Person struct { Name string `json:"name,omitempty"` Age int `json:"age,string,omitempty"` Nicknames []string `json:"nicknames"` }
""の中はカンマ区切りで記載しますが、スペースを空けてはいけません。
左から順にフィールド名、型、空や数値0の場合の対応です。
フィールド名は省略できないので、変数定義から変更しない場合は、カンマだけを記述します。
omitemptyとすると、空や数値0の場合に返す値に含まれなくなります。
また、type定義したstructの場合、omitemptyを有効にするには、定義の型をポインタにする必要があります。
type T struct { } type Person struct { T *T `json:",omitempty"` }
変換内容のカスタマイズ
Marshal、Unmarshalそれぞれ次のように、処理内容を書き換えることができます。
func (p *Person) UnmarshalJSON(b []byte) error { // メソッド(指定した型限定となる)。 中身を変更するため、ポインタレシーバー type Person2 struct { // 新たにローカル型を定義。Personを指定、またはPersonを継承してしまうと、このメソッドを有することになり解決できずstack overflowとなるため Name string } var p2 Person2 err := json.Unmarshal(b, &p2) if err != nil { fmt.Println(err) } p.Name = p2.Name + "!" return err } func (p Person) MarshalJSON() ([]byte, error) { // メソッド(指定した型限定となる)。 v, err := json.Marshal(&struct { // この関数内でのみ使用する構造体なので、定義と中身の指定を連続で行う Name string }{ Name: "Mr." + p.Name, }) return v, err }
上記の処理内容はあくまで例ですので、返り値の型さえ気をつければ、自由に変更できます。
なお、フィールド名等は「変数からJSON」で紹介した、
type定義で記述したjson変換時の各種指定ではなく、こちらのカスタマイズした内容が反映されます。
そのため、頭文字を小文字にしたい場合には、改めて処理の中に記載します。
func (p Person) MarshalJSON() ([]byte, error) { // メソッド(指定した型限定となる)。 v, err := json.Marshal(&struct { Name string `json:"name"` // nameと出力するように変更。定義のフィールド名は、レシーバーの型と合わせる必要がある }{ Name: "Mr." + p.Name, }) return v, err }