はじめに
Goの構造体をJSON出力する方法をまとめてみました。
検証方法
以下のようなPerson構造体をJSON出力していきます。
type Person struct {
Name string
Age int
gender string
}
また、JSON出力した結果を見やすくするために、Mrashal
ではなくMrashalIndent
を使ってフォーマットしたものを出力するようにしています。
package main
import (
"fmt"
"encoding/json"
)
func main() {
p := Person{
Name: "Mike",
Age: 20,
gender: "male",
}
m, _ := json.MarshalIndent(p,""," ")
fmt.Println(string(m))
}
方法1: そのままMarshalする
まずは、特に何もせずにそのまま出力すると以下のような出力が得られます。
{
"Name": "Mike",
"Age": 20
}
プライベートフィールドであるgender
は出力されず、パブリックフィールドのみ出力されました。
また、出力されたキーにはフィールド名が適応されます。
方法2: jsonタグをつけた構造体をMarshalする
Person構造体にjsonタグをつけると、タグに指定した値がキーとして反映されます。
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
gender string `json:"gender"`
}
{
"name": "Mike",
"age": 20
}
ちゃんと指定した値がキーとして反映されますが、プライベートフィールドは反映されないです。
方法3: Marshalerインターフェースを実装した構造体をMarshalする
では、プログラムとしてはgender
フィールドを外部のパッケージからは参照されたくないが、JSON出力したいとなった場合はどうすればよいでしょうか?
実は、encoding/json
パッケージにはMarshalerというインターフェースが提供されています。
type Marshaler
type Marshaler interface { MarshalJSON() ([]byte, error) }
Marshaler is the interface implemented by types that can marshal themselves into valid JSON.
Marshalerを実装した構造体に対してMarshalすると、Marshaler#MarshalJSON()
の実装が適応されます。
例えば、Person
構造体の各フィールドをプライベートにしてカプセル化して、外部からの参照を避け、その上でそれぞれのフィールドはJSONで出力の対象にしたいとします。
このような時に、Person
構造体にMarshalJSON
メソッドを実装することで、柔軟にJSON出力が可能となります。
type Person struct {
name string
Age int
gender string
}
func (p Person) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Name string `json:"name"`
Age int `json:"age"`
Gender string `json:"gender"`
}{
Name: p.name,
Age: p.age,
Gender: p.gender,
})
}
{
"name": "Mike",
"age": 20,
"gender": "male"
}
プライベートなフィールドもちゃんとJSON出力できるようになりました。
まとめ
基本的に方法2
を採用して、柔軟にカスタマイズしたい場合は対象の構造体にMarshaler
を実装すればOK。