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は、使用頻度も高いと思いますので、少しでも理解の助けになればと思います!
Discussion