GW何をしようかと考えた末に、久しぶりにGoを触ってみようかなと思いまして、JSONの使い方を調べてみました。(Goを触るのが1年半ぶりくらいなので、A Tour of Goをやり直しました。Goはドキュメントが非常によく整備されていて助かります。)
ポイント
encoding/json パッケージに大体の機能がある
encoding
パッケージにはバイト文字列やテキスト文字列をエンコーディングする関数や構造体が定義されています。その中に json
パッケージがあり、JSON文字列を扱う関数や構造体が定義されています。
Encoding
Encodingするには json.Marshal
を使います。
func Marshal(v interface{}) ([]byte, error)
引数に与えられた値をJSON文字列としてバイトのスライスで返してくれます。
type colorGroup struct { ID int Name string Colors []string } // Marshal // go type to json string group := colorGroup{ ID: 1, Name: "Reds", Colors: []string{"Crimson", "Red", "Ruby", "Maroon"}, } b, err := json.Marshal(group) if err != nil { log.Fatal(err) } os.Stdout.Write(b) // output // {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
基本的な型は Marshal
でエンコーディングすることができますが、Channel
, complex
, function
はエンコーディング することができません。また、ポインタはエンコーディングできますが、ポインタが指し示す値が対象になるようです。
Decoding
Decodingするには json.Unmarshal
を使います。
func Unmarshal(data []byte, v interface{}) error
引数にJSON文字列を渡すことでデコーディングしてくれます。
type colorGroup struct { ID int Name string Colors []string } // UnMarshal // json string to go type groupString := `{ "id": 1, "name": "Orange", "colors": ["Red", "Ruby"] }` var unMarshalColor colorGroup json.Unmarshal([]byte(groupString), &unMarshalColor) fmt.Println(unMarshalColor) // output // {1 Orange [Red Ruby]}
タグを使ったカスタマイズ
Encoding と Decoding では、構造体にタグを使うことで振る舞いを変更することができます。構造体のタグについては詳しく知らないんですが、構造体のフィールドに追加の属性で文字列を追加することができ、この文字列のことをタグというらしいです。タグはリフレクションで読み取ることが出来るようです。
タグの使用例としてJSONのフィールド名を変更することができます。タグは json
をキーとします。 以下の構造体では ID
フィールドにタグを付けてフィールド名を変更しています。
type colorGroup struct { ID int `json:"number"` Name string Colors []string }
colorGroup
をEncodingすると、以下のJSONになります。 ID
フィールドが number
としてEncodingされていますね。
{"number":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
上記のJSONをDecodingすると、以下の値になります。 number
が ID
フィールドにマッピングされています。
{1 Reds [Crimson Red Ruby Maroon]}
また、タグに omitempty
を付けることで、フィールドが特定の値(0やfalse、nilなど)のときにEncodingから省略するように出来ます。例えば以下の構造体では ID
に omitempty
を付けています。
type colorGroup struct { ID int `json:"number"` Name string Colors []string }
これをEncodingすると、 ID
が省略されます。
group := colorGroup{ ID: 0, Name: "Reds", Colors: []string{"Crimson", "Red", "Ruby", "Maroon"}, } // output // {"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
Streaming で Encode と Decode
jsonパッケージにはJSONをStreamingで読み込み・書き込みするための Decoder
Encoder
型を定義しています。それぞれ NewDecoder
NewEncoder
で io.Reader
io.Writer
インターフェイスをラップした値を取得できます。これらの型を使えば、HTTPやWebSocketでJSONをやり取りする事ができるようになります。
使い方はこんな感じになります。標準入力で読み込んだ値を Decode し、キーが Name
の値だけを標準出力に向けて Encode します。関数の最初の2行で Decoder
Encoder
を作成しています。
func main() { dec := json.NewDecoder(os.Stdin) enc := json.NewEncoder(os.Stdout) for { var v map[string]interface{} if err := dec.Decode(&v); err != nil { log.Println(err) return } for k := range v { if k != "Name" { delete(v, k) } } if err := enc.Encode(&v); err != nil { log.Println(err) } } }
終わりに
GoでJSONを扱う方法は調べるとまだまだ出てくるのですが、とりあえずの基本としてはこのような内容を抑えておけば良さそうです。標準のパッケージでJSONを扱う事ができるのはかなり便利ですね。そして、何より直感的に書く事ができるので迷う事なく理解できた感じがします。