takuroooのブログ

勉強したこととか

Go JSONをデコードする

jsonパッケージのDecoderを使うとjsonデータを簡単にパースできる。

golang.org

目次

変数名で対応付ける

package main

import (
    "encoding/json"
    "fmt"
    "strings"
)

func main() {
    json_data := `{"name":"Gopher","age":10}` // 入力のjsonデータ

    var d struct {
        Name string
        Age  int
    }

    decoder := json.NewDecoder(strings.NewReader(json_data))
    err := decoder.Decode(&d)
    fmt.Println(d.Name, d.Age, err) // Gopher 10 <nil>
}
  • json.NewDecoder()json.Decorderのポインタを取得する。
  • json.NewDecoder()にはio.Readerを渡さなければいけないので、strings.NewReader(json_data)strings.Readerのポインタを渡すようにしている。

jsonデータのkeyとデータを受け取る変数名が同じだと自動で対応づけてくれるらしい。最後の出力は見ると"name":"Gopher"はNameに、"age":10はAgeに紐づいているのが分かる。
名前の対応付がうまくいかないと値が代入されない。試しに入力のjsonのageをheightに変更すると値が代入されないことがわかる。

func main() {
    json_data := `{"name":"Gopher","height":10}` // ageをheightに変更した

    var d struct {
        Name string
        Age  int
    }

    decoder := json.NewDecoder(strings.NewReader(json_data))
    err := decoder.Decode(&d)
    // d.Ageに値が代入されない
    fmt.Println(d.Name, d.Age, err) // Gopher 0 <nil>
}

構造体タグ名で対応付ける

構造体にタグ(json:xxx)を付与するとDecorderがそのタグを使って値を代入してくれる。

func main() {
    json_data := `{"Name":"Gopher","Age":10}`

    var d struct {
        ID  string `json:"name"` // jsonのkeyと同じ名前を指定する
        Old int    `json:"age"`  // 大文字小文字は区別されない
    }

    decoder := json.NewDecoder(strings.NewReader(json_data))
    err := decoder.Decode(&d)
    // jsonのkeyと変数名は一致していないが値が代入されている
    fmt.Println(d.ID, d.Old, err) // Gopher 10 <nil>
}

json:がないと値の代入はうまくいかない。

// これだとうまく代入されない
var d struct {
    ID  string `"name"`
    Old int    `"age"`
}

一致しないkeyがあったときにエラーを返す

これまでの例では一致しないkeyがあってもerr := decoder.Decode(&d)でerrが帰ってくることはなかった。(常にnilだった)
decoder.DisallowUnknownFields()をコールしておくと、一致しないkeyがあったときにerrorとして返してくれる。

func main() {
    json_data := `{"name":"Gopher","age":10}`

    var d struct {
        Name string `json:"name"` // ageに対応する変数がない
    }

    decoder := json.NewDecoder(strings.NewReader(json_data))
    decoder.DisallowUnknownFields() // Decodeの前にコールする
    err := decoder.Decode(&d)
    // ageに対応する変数がなかったのでerrが返ってくる
    fmt.Println(d.Name, err) // Gopher json: unknown field "age"
}