zoukankan      html  css  js  c++  java
  • go语言结构体转map的方法

    使用json序列化与反序列化的方式(有一个数字转换的坑)

    package t8
    
    import (
        "encoding/json"
        "fmt"
        "testing"
    )
    
    type Student struct{
        Name string `json:"name"`
        Age int `json:"age"`
    }
    
    // JSON序列化方式
    func jsonStructToMap(stuObj *Student) (map[string]interface{}, error){
        // 结构体转json
        strRet, err := json.Marshal(stuObj)
        if err != nil{
            return nil, err
        }
        // json转map
        var mRet map[string]interface{}
        err1 := json.Unmarshal(strRet, &mRet)
        if err1 != nil{
            return nil, err1
        }
        return mRet, nil
    }
    
    
    func TestJsonMethod(t *testing.T) {
        // 测试 struct使用json直接转map
        stuObj1 := Student{
            Name: "whw",
            Age: 28,
        }
        mRet, err := jsonStructToMap(&stuObj1)
        if err != nil{
            panic(fmt.Sprintf("json方式出错: %s 
    ", err.Error()))
        }
        // 查看一下转换后的结果
        for key, val := range mRet{
            fmt.Printf("key: %v, value: %v, typeValue: %T 
    ", key, val, val)
        }
        /*
            key: name, value: whw, typeValue: string
            key: age, value: 28, typeValue: float64  ——————————  注意这里age变成了 float64!!!
        */
    }

    使用反射将单层的struct转换为map

    package t8
    
    import (
        "fmt"
        "reflect"
        "testing"
    )
    
    //type Student struct{
    //    Name string `json:"name"`
    //    Age int `json:"age"`
    //}
    
    // ToMap 结构体转为Map[string]interface{}
    func StructToMapReflect(in interface{}, tagName string) (map[string]interface{}, error) {
        out := make(map[string]interface{})
    
        v := reflect.ValueOf(in)
        if v.Kind() == reflect.Ptr {
            v = v.Elem()
        }
    
        if v.Kind() != reflect.Struct { // 非结构体返回错误提示
            return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v)
        }
    
        t := v.Type()
        // 遍历结构体字段
        // 指定tagName值为map中key;字段值为map中value
        for i := 0; i < v.NumField(); i++ {
            fi := t.Field(i)
            if tagValue := fi.Tag.Get(tagName); tagValue != "" {
                out[tagValue] = v.Field(i).Interface()
            }
        }
        return out, nil
    }
    
    func TestReflectMethod(t *testing.T) {
        stuObj := Student{
            Name: "wanghw",
            Age: 22,
        }
    
        m2, _ := StructToMapReflect(&stuObj,"json")
        for key, val := range m2{
            fmt.Printf("key: %s, val: %v, typeVal: %T 
    ", key, val, val)
        }
        /*
            key: name, val: wanghw, typeVal: string
            key: age, val: 22, typeVal: int       ——————  这里正常了,age还是int类型
        */
    }

    使用structs包转换单层的struct为map

    首先需要下载structs包

    go get github.com/fatih/structs

    代码

    package t8
    
    
    import (
        "fmt"
        "github.com/fatih/structs"
        "testing"
    )
    
    type Student struct {
        Name string `json:"name"`
        Age  int    `json:"age"`
    }
    
    func TestStructsMethod(t *testing.T) {
    
        stuObj := Student{
            Name: "naruto",
            Age:  23,
        }
    
        m3 := structs.Map(&stuObj)
        for key, val := range m3 {
            fmt.Printf("key: %s, val: %v, typeVal: %T 
    ", key, val, val)
        }
    
        // key: Name, val: naruto, typeVal: string
        // key: Age, val: 23, typeVal: int
    
    }

    使用structs包或反射的方法转换嵌套的结构体为map

    package t8
    
    import (
        "fmt"
        "github.com/fatih/structs"
        "reflect"
        "testing"
    )
    
    // 嵌套结构体转
    // 用户信息
    type UserInfo struct {
        Name    string  `json:"name" structs:"name"`
        Age     int     `json:"age" structs:"age"`
        Profile Profile `json:"profile" structs:"profile"`
    }
    
    // 配置信息
    type Profile struct {
        Hobby string `json:"hobby" structs:"hobby"`
    }
    
    // 声明一个全局user
    var userObj = UserInfo{
        Name: "whw",
        Age:  18,
        Profile: Profile{
            Hobby: "computer",
        },
    }
    
    // TODO 1、structs转换方法
    func TestStructsMethod(t *testing.T) {
        m3 := structs.Map(&userObj)
        for k, v := range m3 {
            fmt.Printf("key:%v value:%v value type:%T
    ", k, v, v)
        }
        /*
            key:name value:whw value type:string
            key:age value:18 value type:int
            key:profile value:map[hobby:computer] value type:map[string]interface {}
        */
    }
    
    // TODO 2、使用反射转成单层map(注意结构体中不能有重复的字段!!!)
    // ToMap2 将结构体转为单层map
    func ToMap2(in interface{}, tag string) (map[string]interface{}, error) {
    
        // 当前函数只接收struct类型
        v := reflect.ValueOf(in)
        if v.Kind() == reflect.Ptr { // 结构体指针
            v = v.Elem()
        }
        if v.Kind() != reflect.Struct {
            return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v)
        }
    
        out := make(map[string]interface{})
        queue := make([]interface{}, 0, 1)
        queue = append(queue, in)
    
        for len(queue) > 0 {
            v := reflect.ValueOf(queue[0])
            if v.Kind() == reflect.Ptr { // 结构体指针
                v = v.Elem()
            }
            queue = queue[1:]
            t := v.Type()
            for i := 0; i < v.NumField(); i++ {
                vi := v.Field(i)
                if vi.Kind() == reflect.Ptr { // 内嵌指针
                    vi = vi.Elem()
                    if vi.Kind() == reflect.Struct { // 结构体
                        queue = append(queue, vi.Interface())
                    } else {
                        ti := t.Field(i)
                        if tagValue := ti.Tag.Get(tag); tagValue != "" {
                            // 存入map
                            out[tagValue] = vi.Interface()
                        }
                    }
                    break
                }
                if vi.Kind() == reflect.Struct { // 内嵌结构体
                    queue = append(queue, vi.Interface())
                    break
                }
                // 一般字段
                ti := t.Field(i)
                if tagValue := ti.Tag.Get(tag); tagValue != "" {
                    // 存入map
                    out[tagValue] = vi.Interface()
                }
            }
        }
        return out, nil
    }
    
    func TestStructToSingleMap(t *testing.T) {
        m4, _ := ToMap2(&userObj, "json")
        for k, v := range m4 {
            fmt.Printf("key:%v value:%v value type:%T
    ", k, v, v)
        }
        /*
            key:name value:whw value type:string
            key:age value:18 value type:int
            key:hobby value:computer value type:string
        */
    }

    参考博客

    https://www.liwenzhou.com/posts/Go/struct2map/

  • 相关阅读:
    POJ 2955
    POJ 1276 多重背包
    UVA 11584 划分回文字串
    Uva 11400 照明系统
    POJ 2677 Tour
    Uva 437 巴比伦塔 && UVA10003
    12563 Jin Ge Jin Qu hao
    最小公共祖先 (Tarjan) POJ1470
    DB2
    SQLserver数据库
  • 原文地址:https://www.cnblogs.com/paulwhw/p/14148124.html
Copyright © 2011-2022 走看看