LoginSignup
3
4

More than 5 years have passed since last update.

Go言語Marshal系インターフェースの拡張で使えるNoMethodイディオム

Posted at

NoMethod

Go言語、例えばJSONで、特に構造体などの(Un)Marshalerインターフェースを実装するとき、
外部ライブラリのJSONパーサを利用したかったり、ちょっとした処理を追加したいだけで基本的な処理は標準ライブラリと同じ処理をしてほしいときがあります。
しかし単に呼び直すと再実装されたMarshalメソッドを呼び出すことになるのでループしてしまいます。
メソッドを持たない別の型を宣言しラップすることでこれを解決できます。


type Gopher struct{}

func (g *Gopher) MarshalJSON() ([]byte, error) {
    type NoMethod Gopher
    g.onJSONEncoding() //行いたい処理
    raw := NoMethod(*g)
    return json.Marshal(raw)
}

応用

もう一つ、例えばTime型などjsonでサポートされていない型に対応させたいとき、Unmarshalメソッドを実装するために別の型を宣言しますがその型をそのままメンバにするとtime.Time型を直接使うのと比べていろいろと扱いづらいと思います。
これは元の型を埋め込んでいる冗長なメンバを持った一時的な構造体を定義することで解決できます。


type Time time.Time

func (t *Time) UnmarshalJSON(b []byte) error {
    var tt time.Time
    tt, err := time.Parse(`"2006-01-02"`, string(b))
    *t = Time(tt)
    return err
}

type Gopher struct {
    Birthday time.Time
}

func (g *Gopher) UnmarshalJSON(data []byte) error {
    type NoMethod Gopher
    var gg struct {
        Birthday Time
        *NoMethod
    }
    gg.NoMethod = (*NoMethod)(g)
    if err := json.Unmarshal(data, &gg); err != nil {
        return err
    }
    g.Birthday = time.Time(gg.Birthday)
    return nil
}

GoPlayground
https://play.golang.org/p/lVSwnkJFDLv

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4