GolangのMarshalとUnMarshalの使い方を学んだので、メモしておきます。
ネットワークプログラミングをする時に、使用する可能性がかなり高いです。
<目次>
UnMarshalについて
最初にUnMarshalについて説明します。
UnMarshalは、ネットワーク越しに送られたデータ(例えばJson)をGo言語のStruct構造体に変換してくれます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package main import ( "encoding/json" "fmt" ) type Book struct { Title string Price int } func main() { // Unmarshal - json -> go struct b := []byte(`{"title": "Harry Potter", "price": 20}`) var book Book if err := json.Unmarshal(b, &book); err != nil { fmt.Println(err) } fmt.Println(book.Title, book.Price) } |
上記は、Book Structを用意して、byte(ネットワーク越しのjsonデータはbyteの形式で送られてくる)データをUnMarshalしています。
プログラムを実行してみましょう。
1 2 |
$ go run main.go Harry Potter 20 |
注意するべき点は、BookのTitleとNameです。名前の先頭が大文字でないとデータの変換ができません。Go言語では、先頭を大文字にするとPublic、小文字にするとPrivate扱いになるからです。
少し、試してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package main import ( "encoding/json" "fmt" ) type Book struct { title string price int } func main() { // Unmarshal - json -> go struct b := []byte(`{"title": "Harry Potter", "price": 20}`) var book Book if err := json.Unmarshal(b, &book); err != nil { fmt.Println(err) } fmt.Println(book.title, book.price) } |
Bookのtitleとpriceを小文字にしました。この状態でプログラムを実行するとデータ変換はされず、それぞれのTypeのデフォルト値が表示されます。(string->空文字、int -> 0)
1 2 |
$ go run main.go 0 |
Marshalについて
Marshalは、GoのStructをjsonに変換します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package main import ( "encoding/json" "fmt" ) type Book struct { Title string Price int } func main() { // Unmarshal - json -> go struct b := []byte(`{"title": "Harry Potter", "price": 20}`) var book Book if err := json.Unmarshal(b, &book); err != nil { fmt.Println(err) } fmt.Println(book.Title, book.Price) // Marshal - go struct -> json v, _ := json.Marshal(book) fmt.Println(string(v)) } |
プログラムを実行してみましょう。
1 2 3 |
$ go run main.go Harry Potter 20 {"Title":"Harry Potter","Price":20} # marshal data |
jsonに変換されましたね。
JSONのカラム変更
通常、JSONのカラムは小文字が使われます。そのため、TitleとPriceは小文字になっていることが理想です。
1 2 |
// こうなってほしい {"title":"Harry Potter","price":20} |
便利なことに、Go言語では任意の形式に変換する術を用意しています。
Book Structを以下の様に変更してください。
1 2 3 4 |
type Book struct { Title string `json:"title"` Price int `json:"price"` } |
プログラムを実行します。
1 2 |
$ go run main.go {"title":"Harry Potter","price":20} |
Title->title、Price->priceに変換されていることがわかります。
データ型の変換
その他にもint->stringに変換することも可能です。
1 2 3 4 5 6 7 |
type Book struct { Title string `json:"title"` Price int `json:"price,string"` # stringを付与 } ... b := []byte(`{"title": "Harry Potter", "price": "20"}`) // "20"に変更 |
1 2 3 |
$ go run main.go Harry Potter! 20 {"title":"Harry Potter","price":"20"} |
データの秘匿
戻り値のデータの一部を隠したい場合もあると思います。
例えば、パスワードとかですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package main import ( "encoding/json" "fmt" ) type Book struct { Title string `json:"title"` Price int `json:"price,string"` Password string `json:"-"` } func main() { // Unmarshal - json -> go struct b := []byte(`{"title": "Harry Potter", "price": "20", "password": "hoge"}`) var book Book if err := json.Unmarshal(b, &book); err != nil { fmt.Println(err) } fmt.Println(book.Title, book.Price, book.Password) // Marshal - go struct -> json v, _ := json.Marshal(book) fmt.Println(string(v)) } |
Passwordを新しく追加しました。その場合のjsonタグには「-」を指定しています。
プログラムを実行するとPasswordが表示されないことがわかります。
1 2 3 |
$ go run main.go Harry Potter 20 {"title":"Harry Potter","price":"20"} |
omitemptyについて
omitemptyは、データが空の場合にデータを非表示にするタグです。
例えば、Titleを空にしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package main import ( "encoding/json" "fmt" ) type Book struct { Title string `json:"title,omitempty"` Price int `json:"price,string"` Password string `json:"-"` } func main() { // Unmarshal - json -> go struct b := []byte(`{"title": "", "price": "20", "password": "hoge"}`) // title -> "" var book Book if err := json.Unmarshal(b, &book); err != nil { fmt.Println(err) } fmt.Println(book.Title, book.Price, book.Password) // Marshal - go struct -> json v, _ := json.Marshal(book) fmt.Println(string(v)) } |
実行します。
1 2 3 |
$ go run main.go 20 {"price":"20"} |
Marshalのカスタマイズ
Marshalをカスタマイズすることもできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package main import ( "encoding/json" "fmt" ) type Book struct { Title string `json:"title,omitempty"` Price int `json:"price,string"` Password string `json:"-"` } func (b Book) MarshalJSON() ([]byte, error) { v, err := json.Marshal(&struct { Title string }{ Title: b.Title + "!", }) return v, err } func main() { // Unmarshal - json -> go struct b := []byte(`{"title": "Harry Potter", "price": "20", "password": "hoge"}`) var book Book if err := json.Unmarshal(b, &book); err != nil { fmt.Println(err) } fmt.Println(book.Title, book.Price, book.Password) // Marshal - go struct -> json v, _ := json.Marshal(book) fmt.Println(string(v)) } |
「MarshalJSON」でないとカスタマイズできません。Marshalが呼ばれた時に自動的にMarshalJSONメソッドが呼ばれる様になります。
プログラムを実行してみましょう。
1 2 3 |
$ go run main.go Harry Potter 20 {"Title":"Harry Potter!"} |
UnMarshalのカスタマイズ
Marshalと同様にUnMarshalも「UnmarshalJSON」を使用すれば、カスタマイズできます。
1 2 3 4 5 6 7 8 9 10 11 12 |
func (book *Book) UnmarshalJSON(b []byte) error { type UnMarshalBook struct { Title string } var ub UnMarshalBook err := json.Unmarshal(b, &ub) if err != nil { log.Fatal(err) } book.Title = ub.Title + "!" return err } |
プログラムを実行します。
1 2 3 |
$ go run main.go Harry Potter! 0 # !が付与 {"Title":"Harry Potter!!"} |
おわりに
前述の通り、MarshalとUnMarshalは、ネットワークプログラミングで使用用途が高いものだと思います。
しっかり、理解していきたいですね。
それでは、また!
コメントを残す
コメントを投稿するにはログインしてください。