🚙
[golang]構造体をmap[string]interface{}に変換する
はじめに
手打ちでmap[string]interface{}作るのだるって思ったので、自動で構造体から生成できる方法を調べてみました。
UnexportedField以外要素からmapを作る部分に苦労しました。
また、構造体が入れ子になっている場合に関しても苦労しました。
json.Marshalとjson.Unmarshalを利用する
結論から言うと、こちらの方法で解決しました。
はじめにで述べた、苦労した2点が出来るようになっています。
コードは以下です。
struct.go
type PrimaryID struct {
ID int32 `json:"-"`
HashID string `json:"hash_id"`
}
type User struct {
tableName struct{}
PrimaryID
Name string `json:"name"`
}
json.go
func StructToJsonTagMap(data interface{}) (map[string]interface{}, error) {
jsonStr, err := json.Marshal(data)
if err != nil {
return nil, err
}
out := new(bytes.Buffer)
// JSONの整形
err = json.Indent(out, jsonStr, "", " ")
if err != nil {
return nil, err
}
var mapData map[string]interface{}
if err := json.Unmarshal([]byte(out.String()), &mapData); err != nil {
return nil, err
}
return mapData, err
}
[WIP]構造体から直接map[string]interface{}を作成する
こちらでも出来るはずですが、僕は諦めました。
入れ子になった構造体からmapを作成できる方いませんか???
コメントで教えていただけると助かります。
json.go
func StructToJsonTagMap(data interface{}) map[string]interface{} {
result := make(map[string]interface{})
elem := reflect.ValueOf(data).Elem()
size := elem.NumField()
//最初はテーブル名のため i=1から
for i := 1; i < size; i++ {
field := elem.Type().Field(i).Tag.Get("json")
if field == "-" {
continue
}
value := elem.Field(i).Interface()
result[field] = value
}
return result
}
[WIP]tagでkeyを指定しない場合
json.go
func StructToMap(data interface{}) map[string]interface{} {
result := make(map[string]interface{})
elem := reflect.ValueOf(data).Elem()
size := elem.NumField()
for i := 0; i < size; i++ {
field := elem.Type().Field(i).Name
value := elem.Field(i).Interface()
result[field] = value
}
return result
}
環境
- MacBook Air (M1, 2020)
- go -v 1.15
- echo -v 4.3.0
- Docker version 20.10.8, build 3967b7d
- docker-compose version 1.29.2, build 5becea4c
Discussion