JSONと構造体を相互に変換する。
JSONとはWeb上でデータをやり取りする際によく用いられるデータの記述方式。
encoding/jsonという標準パッケージを用いることで、JSONのデータをGoの構造体として扱い、処理をすることが可能。
json.Unmarshal関数でJSONを構造体に変換する
encoding/jsonはJSONを扱う標準パッケージ。
ネットワーク越しにJSONで入ってきたデータをPersonという構造体に格納し、再度JSONに変換して送る処理を想定する。
JSONのデータはbyteで作成し、変数bに代入する。続いて、Person型の変数pを宣言し、json.Unmarshal関数に変数bとポインタの変数pを渡す。
エラーハンドリングをして、エラーがなければ変数pのそれぞれの値を表示してみる。
次のコードを実行すると、JSONのデータが構造体Personに変換されて表示されることが確認できる。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string
Age int
Nicknames []string
}
func main() {
b := []byte(`{"name":"mike","age":20,"nicknames":["a","b","c"]}`)
var p Person
if err := json.Unmarshal(b, &p); err != nil {
fmt.Println(nil)
}
fmt.Println(p.Name, p.Age, p.Nicknames)
}
※コードの意味が分かりにくかったので補足
type Person struct {
Name string
Age int
Nicknames []string
}
Personという構造体(struct)を定義します。この構造体は、名前(Name)、年齢(Age)、およびニックネームのリスト(Nicknames)を持ちます。
b := []byte(`{"name":"mike","age":20,"nicknames":["a","b","c"]}`)
JSON文字列をバイトスライスに変換し、変数bに格納します。これは、後で構造体にデコードするためのデータです。
if err := json.Unmarshal(b, &p); err != nil {
fmt.Println(nil)
}
json.Unmarshal関数を使用して、バイトスライスbからPerson型の変数pにデコードします。エラーが発生した場合は、fmt.Println(nil)を実行します。
fmt.Println(p.Name, p.Age, p.Nicknames)
デコードされた構造体の内容を標準出力に表示します。具体的には、名前、年齢、およびニックネームのリストを出力します。
※補足終わり
構造体Personのフィールドは、パブリックなので頭文字を大文字にしている。ただ、json.Unmarshal関数は大文字か小文字かに関わらず名前が一致すればよいので、問題なく構造体Personに値が代入されている。
JSONのキーの頭文字が大文字でも問題なく値は代入される。ただし、一致しない名前にしてしまうと値が代入されない。次のコードでは、JSONのキーが「age」でなく「ge」になっているので構造体Personのageの値はデフォルト値である0が表示される
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string
Age int
Nicknames []string
}
func main() {
b := []byte(`{"name":"mike","ge":20,"nicknames":["a","b","c"]}`)
var p Person
if err := json.Unmarshal(b, &p); err != nil {
fmt.Println(nil)
}
fmt.Println(p.Name, p.Age, p.Nicknames)
}
json.Marshal関数で構造体をJSONに変換する。
構造体のデータをJSONに変換するには、json.Marshal関数を使う。引数に構造体Personの変数pを渡し、エラーは無視して変数vに代入する。
このとき、変数vはbyte配列なので、次のコードのようにstring型で表示すると変数pからJSONに変換されて表示される。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string
Age int
Nicknames []string
}
func main() {
b := []byte(`{"name":"mike","ge":20,"nicknames":["a","b","c"]}`)
var p Person
if err := json.Unmarshal(b, &p); err != nil {
fmt.Println(nil)
}
fmt.Println(p.Name, p.Age, p.Nicknames)
v, _ := json.Marshal(p)
fmt.Println(string(v))
}
JSONに変換する際のキー名を指定する
構造体Personのフィールド名はエクスポートしているため、JSONに変換した際もキーの頭文字は大文字になっている。
このとき、構造体のフィールド名がJSONのキーに変換されるときの名前を指定することができる。
構造体Personのフィールドの後ろで「json:"name"」のように名前を指定して再度コードを実行すると、JSONのキーが指定した通り小文字になっていることが分かる。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"` //キー名の指定
Age int
Nicknames []string
}
func main() {
b := []byte(`{"name":"mike","ge":20,"nicknames":["a","b","c"]}`)
var p Person
if err := json.Unmarshal(b, &p); err != nil {
fmt.Println(nil)
}
fmt.Println(p.Name, p.Age, p.Nicknames)
v, _ := json.Marshal(p)
fmt.Println(string(v))
}
実行結果は以下
↑nameという頭文字が小文字で出力されている。
また、。「json:"nameXXX"」のように指定すると、JSONのキーの名前も変わる。また、json.Unmarshal関数の時も「nameXXX」として扱うので、JSONの中に「nameXXX」という名前のキーが存在しないため、デフォルトとしてから文字列が表示される
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"nameXXX"` //JSONのとき名前を変える
Age int
Nicknames []string
}
func main() {
b := []byte(`{"name":"mike","age":20,"nicknames":["a","b","c"]}`)
var p Person
if err := json.Unmarshal(b, &p); err != nil {
fmt.Println(nil)
}
fmt.Println(p.Name, p.Age, p.Nicknames)
v, _ := json.Marshal(p)
fmt.Println(string(v))
}
JSONでの型変更
構造体とJSONとの間での変換を行う時に、違う型として扱うこともできる。
「json:"age,string"」とすると、json.Marshal関数で構造体Personに渡すJSONのageの値はstring型とする必要がある。
以下のコードを実行するとjson.Marshal関数でJSONに変換したときのageはstring型で表示されるようになる。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age,string` //jsonのときはstring型にする。
Nicknames []string
}
func main() {
b := []byte(`{"name":"mike","age":20,"nicknames":["a","b","c"]}`)
var p Person
if err := json.Unmarshal(b, &p); err != nil {
fmt.Println(nil)
}
fmt.Println(p.Name, p.Age, p.Nicknames)
v, _ := json.Marshal(p)
fmt.Println(string(v))
}
##JSONに表示する際に非表示とする。
構造体の定義の部分で「json:"-"」と指定するとJSON側では無視される。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"-"`
Age int `json:"age,string` //jsonのときはstring型にする。
Nicknames []string
}
func main() {
b := []byte(`{"name":"mike","age":20,"nicknames":["a","b","c"]}`)
var p Person
if err := json.Unmarshal(b, &p); err != nil {
fmt.Println(nil)
}
fmt.Println(p.Name, p.Age, p.Nicknames)
v, _ := json.Marshal(p)
fmt.Println(string(v))
}
Nameの値がから文字列になり、nameを除いてJSONが表示されるようになる。
json.Marshal関数をカスタマイズする
json.marshal関数で構造体をJSONに変換する際の処理を、独自にカスタマイズすることも可能。カスタマイズする場合は、独自の処理をしたい型にMarshalJSONメソッドを実装する。
構造体PersonにMarshalJSONメソッドを実装し、処理を記載する。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"-"`
Age int `json:"age",string` //jsonのときはstring型にする。
Nicknames []string
}
func (p Person) MarshalJSON() ([]byte, error) { //MarshaJSONメソッドを実装
v, err := json.Marshal(&struct { //その場で無名構造体を定義
Name string //無名構造体にNameというフィールドを定義
}{
Name: "Mr." + p.Name, //Nameの値を初期化
})
return v, err
}
func main() {
b := []byte(`{"name":"mike","age":20,"nicknames":["a","b","c"]}`)
var p Person
if err := json.Unmarshal(b, &p); err != nil {
fmt.Println(nil)
}
fmt.Println(p.Name, p.Age, p.Nicknames)
v, _ := json.Marshal(p) //Mashal関数でMarshalJSONメソッドが呼び出される
fmt.Println(string(v))
}
もとになるJSONなnameの値が-で隠れているので元に戻して再度実行する
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string
Age int `json:"age",string` //jsonのときはstring型にする。
Nicknames []string
}
func (p Person) MarshalJSON() ([]byte, error) { //MarshaJSONメソッドを実装
v, err := json.Marshal(&struct { //その場で無名構造体を定義
Name string //無名構造体にNameというフィールドを定義
}{
Name: "Mr." + p.Name, //Nameの値を初期化
})
return v, err
}
func main() {
b := []byte(`{"name":"mike","age":20,"nicknames":["a","b","c"]}`)
var p Person
if err := json.Unmarshal(b, &p); err != nil {
fmt.Println(nil)
}
fmt.Println(p.Name, p.Age, p.Nicknames)
v, _ := json.Marshal(p) //Mashal関数でMarshalJSONメソッドが呼び出される
fmt.Println(string(v))
}
学習に使用した教材
・『入門】Golang基礎入門 + 各種ライブラリ + 簡単なTodoWebアプリケーション開発(Go言語)』M.A EduTech
https://www.udemy.com/course/golang-webgosql/?utm_medium=udemyads&utm_source=bene-msa&utm_campaign=responsive&utm_content=top-1&utm_term=general&msclkid=81e2f24a32cc185d275d953d60760226&couponCode=NEWYEARCAREERJP
・『シリコンバレー一流プログラマーが教える Goプロフェッショナル大全』酒井 潤 (著)
https://www.amazon.co.jp/%E3%82%B7%E3%83%AA%E3%82%B3%E3%83%B3%E3%83%90%E3%83%AC%E3%83%BC%E4%B8%80%E6%B5%81%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E3%81%8C%E6%95%99%E3%81%88%E3%82%8B-Go%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E5%A4%A7%E5%85%A8-%E9%85%92%E4%BA%95-%E6%BD%A4/dp/4046070897