json.Unmarshalとreflectパッケージを使って構造体を生成する
目次
今回は reflect
パッケージと json
パッケージも使って構造体の生成をしてみます。
json.Unmarshal
を使った構造体の生成
以下の構造体を定義します。
1type Msg struct {
2 ID int `json:"id"`
3 Msg string `json:"msg"`
4}
通常、json文字列から構造体を作成するには json.Unmarshal
、または json.NewDecoder
を使います。
1func main() {
2 str := `{"id":1,"msg":"some message here"}`
3
4 var msg Msg
5 json.Unmarshal([]byte(str), &msg)
6
7 # main.Msg{ID:1, Msg:"some message here"} が表示される
8 log.Printf("%#v", msg)
9}
reflect
パッケージと json.Unmarshal
を使った構造体の生成
Goのreflectパッケージを使ってインスタンスを生成する の記事で学んだ
リフレクションと組み合わせて、JSON文字列から構造体のインスタンスを作成する関数 createInstance
を作ります。
以下のようになりました。
1func main() {
2 str := `{"id":1,"msg":"some message here"}`
3
4 var msg Msg
5 # *Msg型が格納される
6 res := createInstance(str, reflect.TypeOf(msg))
7
8 # main.Msg{ID:1, Msg:"some message here"} が表示される
9 log.Printf("%#v", res)
10
11 # 構造体の各フィールドにアクセスするには型アサーションが必要
12 r := res.(*Msg)
13 log.Printf("%#v", r)
14 log.Print("%s", r.ID)
15 log.Print("%s", r.Msg)
16}
17
18# Typeからオブジェクトを生成して、interfaceをUnmarshalに渡す
19func createInstance(str string, typ reflect.Type) interface{} {
20
21 obj := reflect.New(typ).Interface()
22 json.Unmarshal([]byte(str), &obj)
23 return obj
24}
NGなパターン( Elem
を使う)
実装の過程で失敗したコード片も載せておきます。
reflect.New
で生成したインスタンスから Elem()
で要素を取得した場合には
map[string]interface{}
型のオブジェクトが返却されてしまいました。
1func createInstance(str string, typ reflect.Type) interface{} {
2 obj := reflect.New(typ).Elem().Interface()
3 json.Unmarshal([]byte(str), &obj)
4 # map[string]interface{} 型が返却される
5 return obj
6}
これは Unmarshal
に interface{}
型の変数のアドレスを渡したときと同じ挙動です。
1var f interface{}
2err := json.Unmarshal(b, &f)