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)