TL;DR
- Go で
UnmarshalJSONを書くとき、元の型と同じ構造でメソッドを持たないクローン型を一時的な構造体に埋め込めば、特別な処理が必要なフィールドだけを手で扱える。
内容
問題
受け取る JSON によっては、古い日付の形式を読む、値を検証するなど、encoding/json だけでは扱えない処理が必要になる。UnmarshalJSON を一から書くと、一時的な構造体にすべてのフィールドを写す必要があり、フィールドが数十、数百ある型では手間がかかる。
方法
DOB time.Time と Homepage url.URL を持つ Person を例にする。
type Doppelganger Personで、同じ構造でメソッドを持たない型を作る。UnmarshalJSONを持たないので、無限に再帰しない- 問題のフィールドを
stringで宣言し、*Doppelgangerを埋め込んだ一時的な構造体を作る。埋め込んだポインタはレシーバpを指す json.Unmarshal(data, &tmp)を呼ぶと、普通のフィールドは埋め込んだポインタを通して直接pに入り、問題のフィールドだけが文字列としてtmpに入る- 文字列の
DOBをtime.Parse(time.RFC3339, ...)で、Homepageをurl.Parseで読み、結果をpに入れる
func (p *Person) UnmarshalJSON(data []byte) error {
type Doppelganger Person
tmp := struct {
DOB string
Homepage string
*Doppelganger
}{
Doppelganger: (*Doppelganger)(p),
}
// json.Unmarshal(data, &tmp) のあと、DOB と Homepage を手で読む
...
}著者はフィールドの多い型だけでなく、一部に独自の読み込みが必要な小さな型にも使える方法だとしている。
キーワード
- Go
- encoding/json
- 構造体の埋め込み