0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Go言語(プログラミング)入門メモ㉘

Posted at

JSONと構造体を相互に変換する。

JSONとはWeb上でデータをやり取りする際によく用いられるデータの記述方式。
encoding/jsonという標準パッケージを用いることで、JSONのデータをGoの構造体として扱い、処理をすることが可能。

json.Unmarshal関数でJSONを構造体に変換する

encoding/jsonはJSONを扱う標準パッケージ。
ネットワーク越しにJSONで入ってきたデータをPersonという構造体に格納し、再度JSONに変換して送る処理を想定する。
image.png
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)

デコードされた構造体の内容を標準出力に表示します。具体的には、名前、年齢、およびニックネームのリストを出力します。
※補足終わり

実行結果は以下。
image.png

構造体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)

}

出力結果は以下。
image.png
↑ageが0と表示される。

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))

}

出力結果は以下。
image.png

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))

}

実行結果は以下
image.png
↑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))

}

実行結果は以下
image.png

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))

}

結果は以下
image.png

##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))

}

image.png
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))

}

image.png

もとになる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))

}

image.png

学習に使用した教材

・『入門】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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?