使用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/