json.Unmarshalとreflectパッケージを使って構造体を生成する

json.Unmarshalとreflectパッケージを使って構造体を生成する
Page content

今回は reflect パッケージと json パッケージも使って構造体の生成をしてみます。

json.Unmarshal を使った構造体の生成

以下の構造体を定義します。

type Msg struct {
	ID  int    `json:"id"`
	Msg string `json:"msg"`
}

通常、json文字列から構造体を作成するには json.Unmarshal 、または json.NewDecoder を使います。

func main() {
	str := `{"id":1,"msg":"some message here"}`
	
	var msg Msg
	json.Unmarshal([]byte(str), &msg)

	# main.Msg{ID:1, Msg:"some message here"} が表示される
	log.Printf("%#v", msg)	
}

reflect パッケージと json.Unmarshal を使った構造体の生成

Goのreflectパッケージを使ってインスタンスを生成する の記事で学んだ リフレクションと組み合わせて、JSON文字列から構造体のインスタンスを作成する関数 createInstance を作ります。

以下のようになりました。


func main() {
	str := `{"id":1,"msg":"some message here"}`

	var msg Msg
	# *Msg型が格納される
	res := createInstance(str, reflect.TypeOf(msg))

	# main.Msg{ID:1, Msg:"some message here"} が表示される
	log.Printf("%#v", res)

	# 構造体の各フィールドにアクセスするには型アサーションが必要
	r := res.(*Msg)
	log.Printf("%#v", r)
	log.Print("%s", r.ID)
	log.Print("%s", r.Msg)
}

# Typeからオブジェクトを生成して、interfaceをUnmarshalに渡す
func createInstance(str string, typ reflect.Type) interface{} {

	obj := reflect.New(typ).Interface()	
	json.Unmarshal([]byte(str), &obj)
	return obj
}

NGなパターン( Elem を使う)

実装の過程で失敗したコード片も載せておきます。

reflect.New で生成したインスタンスから Elem() で要素を取得した場合には map[string]interface{} 型のオブジェクトが返却されてしまいました。

func createInstance(str string, typ reflect.Type) interface{} {
	obj := reflect.New(typ).Elem().Interface()
	json.Unmarshal([]byte(str), &obj)
	# map[string]interface{} 型が返却される
	return obj
}

これは Unmarshalinterface{} 型の変数のアドレスを渡したときと同じ挙動です。

var f interface{}
err := json.Unmarshal(b, &f)

参考にさせていただいたサイト

関連記事

soudegesu avatar
About soudegesu
Software Engineer
comments powered by Disqus