使用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 \n", err.Error()))
    }
    // 查看一下转换后的结果
    for key, val := range mRet{
        fmt.Printf("key: %v, value: %v, typeValue: %T \n", 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 \n", 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"
)

// 需要用structs标签!!!否则转成的map的key都是大写的!!!这个例子没有用structs标签下面转化的map的key的首字母都是大写的 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 \n", 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"
)

// 嵌套结构体转
// 用户信息 需要用structs标签!!!这样转成的map的key就是structs标签对应的!!!
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\n", 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\n", k, v, v)
    }
    /*
        key:name value:whw value type:string
        key:age value:18 value type:int
        key:hobby value:computer value type:string
    */
}

***有些不想转到最终map的字段 —— 加一个map过滤

 

package scripts_stroage

import (
    "fmt"
    "github.com/fatih/structs"
    "testing"
)

// Notice 试一下有不想放到最终map中的字段
type UserInfo struct {
    Id   int    `json:"id" structs:"id"` // Notice 这个字段不想放到最终的map中
    Name string `json:"name" structs:"name"`
    Age  int    `json:"age" structs:"age"`
}

func TestTUI1(t *testing.T) {

    user := UserInfo{
        Id:   123,
        Name: "whw",
        Age:  22,
    }
    m1 := structs.Map(user)
    fmt.Println("m1: ", m1) // map[age:22 id:123 name:whw]
    retMap := make(map[string]interface{})
    for key := range m1 {
        if key == "id" {
            continue
        }
        retMap[key] = m1[key]
    }

    fmt.Println("retMap: ", retMap) // map[age:22 name:whw]
}

 

参考博客