emahiro/b.log

日々の勉強の記録とか育児の記録とか。

自前でUnmarshalを実装したときの panic を回避する

カスタム Struct に自前で Unmarshal を実装して json -> object に decode するときに無限ループを引き起こして panic しないようにするTipsです。

サンプルケースですが、以下のコードは json を decodeす るときに panic を引き起こします。

type Person struct {
    Name string `json:"name"`
    Age int64 `json:"age"`
}

func (p *Person) UnmarshalJSON(data []byte) error {
    if p.Age == 0 {
        p.Age = 10
    }
    return json.Unmarshal(data, p)
}

refs: https://play.golang.org/p/7RtVampOalT

理由は json を decode する対象の Person struct に対して再帰的に UnmarshalJSON をかけてしまい無限ループに陥ってしまうからです。

こう言ったケースでは UnmarshalJSON メソッド内で別の type として Alias を切ることで無限ループを回避できます。

func (p *Person) UnmarshalJSON(data []byte) error {
    if p.Age == 0 {
        p.Age = 10
    }
    type Alias Person
    pp := &struct {
        *Alias
    }{
        Alias: (*Alias)(p),
    }
    return json.Unmarshal(data, pp)
}

ref: https://play.golang.org/p/lymBTGoMbB5

元ネタはこちらの記事です↓

http://choly.ca/post/go-json-marshalling/