前置き
SQLの汎用性があるプログラムを自作中にSQLからデータを読み取る際に、読み取ったデータを配列に変換させる際で汎用性プログラムが作れないか試してみたので、記録する・
説明など
構造体を作ったり操作するためにreflect関数というだいぶ便利なものがあるのでデバッガと組み合わせていろいろと試していた。
ポインタ操作がかなりめんどくさいけど、一つづつ調整していくと出来上がるものができたからだいぶ楽になった。
実装プログラム
main.go
package main
import (
"fmt"
"reflect"
)
func mapToStruct(s map[string]interface{}, i interface{}) {
sv := reflect.ValueOf(i)
if sv.Type().Kind() != reflect.Pointer {
fmt.Println(sv.Type().Kind())
return
}
if len(s) == 0 {
return
}
ii := sv.Elem().Interface()
tStruct := reflect.TypeOf(ii).Elem()
vStruct := reflect.New(tStruct)
ckStruct := reflect.TypeOf(vStruct.Elem().Interface())
for i := 0; i < ckStruct.NumField(); i++ {
f := ckStruct.Field(i)
v := vStruct.Elem().FieldByName(f.Name)
ss := s[f.Name]
switch f.Type.Kind() {
case reflect.Int & reflect.TypeOf(ss).Kind():
v.SetInt(int64(ss.(int)))
case reflect.String & reflect.TypeOf(ss).Kind():
v.SetString(ss.(string))
}
}
out := vStruct.Elem()
v := sv.Elem()
v.Set(reflect.Append(v, out))
}
type User struct {
Name string
Age int
}
func main() {
strmap := map[string]interface{}{
"Name": "bsg",
"Age": 10,
}
strmap2 := map[string]interface{}{
"Name": "bsg1",
"Age": "10",
}
str := []User{}
mapToStruct(strmap, &str)
mapToStruct(strmap2, &str)
fmt.Println(str)
}
この関数を実行すると以下の通り帰ってくる
[{bsg 10} {bsg1 0}]
結果的に、名前に対応したmapの型を合わせないと配列に設定して追加しないし特別なエラーが発生ないことも確認できた。
まとめ
reflect関数とinterfaceの型を組み合わせることで、だいぶ汎用性がある配列を作る関数プログラムができた。
これから、SQLの汎用プログラム作成に役に立つだろう