Goで、json.UnmarshalとMarshalとエンコード
Golangの、UnmarshalとMarshalについて解説してみたいと思います。 ネットワーク越しで、取ってきたデータをGoの構造体に変換したり、Goの構造体からJSONに変換してデータを送信したりと使用する機会も多いと思うので、是非参考にしていただければと思います。
Unmarshal
Unmarshalは、ネットワーク越しに送信されたデータをGoの構造体に変換します。
func Unmarshal(data []byte, v any) error
Unmarshalは、JSON形式で受け取った値を指定した構造体に格納することができます。第1引数にJSON形式のデータを、第2引数に格納したい構造体を指定します。 第2引数の値がnilもしくはポインタではない場合、InvalidUnmarshalErrorを返します。
package main import ( "encoding/json" "fmt" ) type Book struct { Title string Author string Publisher string } func main() { b := []byte(`{"title": "リーダブルコード", "author": "Trevor Foucher", "Publisher": "OREILLY"}`) var book Book if err := json.Unmarshal(b, &book); err != nil { fmt.Println(err) } fmt.Println(book.Title, book.Author, book.Publisher) }
実行してみます。
$ docker-compose up go_1 | running... go_1 | リーダブルコード Trevor Foucher OREILLY
ネットワークで入ってきた、byteのスライスをBook構造体のキーをみて変換してくれるのが、Unmarshalとなります。
Marshal
Goの構造体に格納したデータを、JSON形式に変換してネットワーク越しに送信したい場合に、Marshalを使用します。
func Marshal(v any) ([]byte, error)
Marshalは、引数の値をJSON形式にエンコーディングして返します。
package main import ( "encoding/json" "fmt" ) type Book struct { Title string Author string Publisher string } func main() { b := []byte(`{"title": "リーダブルコード", "author": "Trevor Foucher", "Publisher": "OREILLY"}`) var book Book v, err := json.Marshal(book) if err != nil { fmt.Println(err) } fmt.Println(string(v)) }
実行してみます。
$ docker-compose up go_1 | running... go_1 | {"Title":"リーダブルコード","Author":"Trevor Foucher","Publisher":"OREILLY"}
JSON形式の値が返って来ていることが確認できます。
Marshalを使ってJSON形式で出力をしましたが、キーの名前が大文字になっています。JSON形式でデータを扱う場合、大文字になることはあまり無いため小文字にしてみましょう。小文字で指定をするには、構造体にタグを付けることで対応できます。 Marshalするときには、どのような名前でエンコードするかを指定することができます。
type Book struct { Title string `json:"title"` Author string `json:"author"` Publisher string `json:"publisher"` }
再度実行してみます。
$ docker-compose up go_1 | running... go_1 | {"title":"リーダブルコード","author":"Trevor Foucher","publisher":"OREILLY"}
構造体の頭文字は大文字ですが、タグをつけることでキーが小文字になっていることが確認できます。
データを隠す
このデータは表示させたくないというケースがあると思います。そのような場合は、JSONのタグにハイフンを指定することで、データを隠すことができます。
type Book struct { Title string `json:"title"` Author string `json:"-"` Publisher string `json:"publisher"` }
実行してみます。
$ docker-compose up go_1 | running... go_1 | {"title":"リーダブルコード","publisher":"OREILLY"}
ハイフンを指定した、Authorが表示されていないのが確認できると思います。 著者名を隠すってどんなケースだよ!ですよね笑、題材が悪かったですね笑 パスワードとかkeyとかで使えるのかなと思います!
Marshalを独自カスタマイズ
Marshalを拡張させて、独自に処理を加えてカスタマイズすることもできます。便利ですね!
MarshalJSON
の形で記述しないとカスタマイズすることができないです。Marshalが呼ばれた時に自動的にMarshalJSONメソッドが呼ばれる様になります。
package main import ( "encoding/json" "fmt" ) type Book struct { Title string `json:"title"` Author string `json:"-"` Publisher string `json:"publisher"` } func (b Book) MarshalJSON() ([]byte, error) { v, err := json.Marshal(&struct { Publisher string }{ Publisher: b.Publisher + "Japan", }) return v, err } func main() { b := []byte(`{"title": "リーダブルコード", "author": "Trevor Foucher", "Publisher": "OREILLY"}`) var book Book if err := json.Unmarshal(b, &book); err != nil { fmt.Println(err) } fmt.Println(book.Title, book.Author, book.Publisher) v, err := json.Marshal(book) if err != nil { fmt.Println(err) } fmt.Println(string(v)) }
実行してみます。
$ docker-compose up go_1 | running... go_1 | {"Publisher":"OREILLY Japan"}
OREILLYから、OREILLY Japanに変わってると思います。
Unmarshalを独自カスタマイズ
Marshalと同様にUnmarshalもUnmarshalJSON
を使用すれば、カスタマイズできます。
package main import ( "encoding/json" "fmt" ) type Book struct { Title string `json:"title"` Author string `json:"author"` Publisher string `json:"publisher"` } func (b *Book) UnmarshalJSON(byte []byte) error { type Book2 struct { Title string } var b2 Book2 err := json.Unmarshal(byte, &b2) if err != nil { fmt.Println(err) } b.Title = b2.Title + "-より良いコードを書くためのシンプルで実践的なテクニック" return err } func main() { b := []byte(`{"title": "リーダブルコード", "author": "Trevor Foucher", "Publisher": "OREILLY"}`) var book Book if err := json.Unmarshal(b, &book); err != nil { fmt.Println(err) } fmt.Println(book.Title, book.Author, book.Publisher) v, err := json.Marshal(book) if err != nil { fmt.Println(err) } fmt.Println(string(v)) }
実行してみます。
$ docker-compose up go_1 | running... go_1 | {"title":"リーダブルコード-より良いコードを書くためのシンプルで実践的なテクニック",
Marshalと同様しっかりカスタマイズできていますね! いかがだったでしょうか、UnmarshalとMarshalは、使用頻度も高いと思いますので、少しでも理解の助けになればと思います!