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)