golang map to struct
http://stackoverflow.com/questions/26744873/converting-map-to-struct
func SetField(obj interface{}, name string, value interface{}) error { structValue := reflect.ValueOf(obj).Elem() structFieldValue := structValue.FieldByName(name) if !structFieldValue.IsValid() { return fmt.Errorf("No such field: %s in obj", name) } if !structFieldValue.CanSet() { return fmt.Errorf("Cannot set %s field value", name) } structFieldType := structFieldValue.Type() val := reflect.ValueOf(value) if structFieldType != val.Type() { return errors.New("Provided value type didn't match obj field type") } structFieldValue.Set(val) return nil } type MyStruct struct { Name string Age int64 } func (s *MyStruct) FillStruct(m map[string]interface{}) error { for k, v := range m { err := SetField(s, k, v) if err != nil { return err } } return nil } func main() { myData := make(map[string]interface{}) myData["Name"] = "Tony" myData["Age"] = int64(23) result := &MyStruct{} err := result.FillStruct(myData) if err != nil { fmt.Println(err) } fmt.Println(result) }
从mysql的结果到某个struct
type operConf struct { Id uint32 `sql:"oper_id"` Name string `sql:"oper_name"` MsgRetyTimes uint32 `sql:"msg_retry_times"` MsgRetyInterval uint32 `sql:"msg_retry_interval"` HeartBeartInterval uint32 `sql:"heartbeat_interval"` OfflineDetectTime uint32 `sql:"offline_detect_time"` } func GetOperConf() ([]operConf, error) { host := GetConf().MySql.Host port := GetConf().MySql.Port user := GetConf().MySql.User password := GetConf().MySql.Pwd dbName := GetConf().MySql.Db table := GetConf().MySql.Table sql := new(mysql) defer sql.Close() if err := sql.Connect(host, port, user, password, dbName, table); err != nil { logger.DEBUG(LOG_NAME, "slq.Connect err:%s", err.Error()) return nil, err } sqlStr := "SELECT oper_id, oper_name, msg_retry_times, msg_retry_interval, heartbeat_interval, offline_detect_time" sqlStr += " From " + table result, err := sql.Query(sqlStr) if err != nil { return nil, err } confArr := make([]operConf, len(result)) for i, v := range result { oc := new(operConf) DataToStruct(v, oc) logger.DEBUG(LOG_NAME, "oc:%+v", oc) confArr[i] = *oc } return nil, nil } type mysql struct { m_db *sql.DB } func (this *mysql) Connect(host string, port int, user, password, dbName, table string) error { dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", user, password, host, port, dbName) var err error this.m_db, err = sql.Open("mysql", dsn) if err != nil { fmt.Println("error: %s\n", err.Error()) return err } err = this.m_db.Ping() if err != nil { this.m_db.Close() } return err } func (this *mysql) Close() { this.m_db.Close() } func (this *mysql) Query(sql string) (map[int]map[string]string, error) { if this.m_db == nil { return nil, errors.New("mysql not connect") } var query = strings.TrimSpace(sql) s, err := regexp.MatchString(`(?i)^select`, query) //(?i) igonre upper/lower case if err != nil { return nil, err } if s == false { return nil, errors.New("not select sql") } rows, _ := this.m_db.Query(sql) c, err := this.GetQueryResult(rows) return c, err } func (this *mysql) GetQueryResult(rows *sql.Rows) (map[int]map[string]string, error) { var result = make(map[int]map[string]string) columns, _ := rows.Columns() values := make([]sql.RawBytes, len(columns)) scanArgs := make([]interface{}, len(values)) for i := range values { scanArgs[i] = &values[i] } var n = 0 for rows.Next() { result[n] = make(map[string]string) err := rows.Scan(scanArgs...) if err != nil { return nil, err } for i, v := range values { result[n][columns[i]] = string(v) } n++ } logger.DEBUG(LOG_NAME, "Query Result:%+v", result) return result, nil } func DataToStruct(data map[string]string, out interface{}) { ss := reflect.ValueOf(out).Elem() for i := 0; i < ss.NumField(); i++ { val := data[ss.Type().Field(i).Tag.Get("sql")] name := ss.Type().Field(i).Name logger.DEBUG(LOG_NAME, "tag:%s, tag value:%s, filed name:%s", ss.Type().Field(i).Tag.Get("sql"), val, name) switch ss.Field(i).Kind() { case reflect.String: ss.FieldByName(name).SetString(val) case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64: i, err := strconv.Atoi(val) // fmt.Println("i:", i, name) if err != nil { logger.ERROR(LOG_NAME, "can't not atoi:%v", val) continue } ss.FieldByName(name).SetInt(int64(i)) case reflect.Uint16, reflect.Uint32, reflect.Uint64: i, err := strconv.Atoi(val) // fmt.Println("i:", i, name) if err != nil { logger.ERROR(LOG_NAME, "can't not atoi:%v", val) continue } ss.FieldByName(name).SetUint(uint64(i)) case reflect.Float32, reflect.Float64: f, err := strconv.ParseFloat(val, 64) if err != nil { logger.ERROR(LOG_NAME, "can't not ParseFloat:%v", val) continue } ss.FieldByName(name).SetFloat(f) default: logger.ERROR(LOG_NAME, "unknown type:%+v", ss.Field(i).Kind()) } } return }