golang map to struct

diegodu · · 4450 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

 

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
}

 


有疑问加站长微信联系(非本文作者)

本文来自:博客园

感谢作者:diegodu

查看原文:golang map to struct

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

4450 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传