LoginSignup
1
0

More than 1 year has passed since last update.

Bitfield を使った json.Marshal/Unmarshal の例

Last updated at Posted at 2021-12-03

2021年Goアドベントカレンダー 4日目の記事です。

encoding/json パッケージには Marshaler/Unmarshaler インターフェイスがあります。
インターフェイスの実装を満たす構造体であれば、jsonをGoのデータへマッピングすることや、jsonデータをシリアライズして出力することが出来ます。

type Unmarshaler interface {
    UnmarshalJSON([]byte) error
}
type Marshaler interface {
    MarshalJSON() ([]byte, error)
}

UnmarshalJSON は、インプットの json データをハンドルして Go の型へ変換したい時、
MarshalJSON は、Goの構造体などを json データへシリアライズして出力する際などに利用できます。

MarshalJSON / UnmarshalJSON の実装例

下記のような型を定義して、実装例を示してみたいと思います。

type Bitfield uint8

const (
    x uint8 = 1 << iota
    w
    r
)

Bitfield に以下のようなメソッドを実装すれば、json配列として表現することが出来ます。

  • UnmarshalJSON では、論理和を行いインプットを処理する
  • MarshalJSON では、論理積により判定を行う
func (b *Bitfield) UnmarshalJSON(byt []byte) error {
    var items []string
    if err := json.Unmarshal(byt, &items); err != nil {
        return err
    }
    for _, s := range items {
        switch strings.ToLower(s) {
        case "x":
            *b |= Bitfield(x)
        case "w":
            *b |= Bitfield(w)
        case "r":
            *b |= Bitfield(r)
        default:
        }
    }
    return nil
}

func (b Bitfield) MarshalJSON() ([]byte, error) {
    arr := []string{}
    if uint8(b)&x != 0 {
        arr = append(arr, "x")
    }
    if uint8(b)&w != 0 {
        arr = append(arr, "w")
    }
    if uint8(b)&r != 0 {
        arr = append(arr, "r")
    }
    return json.Marshal(arr)
}

出力例
https://go.dev/play/p/w-dIYugBrO9

func main() {
    blobs := []string{`["x", "w","r"]`, `["x","r"]`, `["r"]`, `[]`}
    for _, blob := range blobs {
        var b Bitfield
        if err := json.Unmarshal([]byte(blob), &b); err != nil {
            log.Fatal(err)
        }
        byte, err := json.Marshal(b)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%d: %s\n", b, byte)
    }
}
7: ["x","x", "w","r"]
5: ["x","r"]
4: ["r"]
0: []
1
0
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
1
0