持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情
前言
今天在撸代码的时候遇到一个问题,在使用json
将结构体转为map的时候发现前后类型发生了变化,这是怎么回事?今天就来看一下在go中将结构体转为map的几种方式,在开发中还是常用的,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
结构体转map[string]interface{}
为了方便下面测试,我们先定义一个结构体如下:
type User struct {
Name string `json:"name"` //姓名
Age int64 `json:"age"` //年龄
}
json包的marshal,unmarshal
先将结构体序列化成[]byte数组,再从[]byte数组序列化成结构体。
func main() {
user := User{Name: "小明", Age: 30}
b, _ := json.Marshal(&user)
var userMap map[string]interface{}
_ = json.Unmarshal(b, &userMap)
for k, v := range userMap{
fmt.Printf("key:%v value:%v value type:%T\n", k, v, v)
}
}
如上示例执行输出结果如下:
key:name value:小明 value type:string
key:age value:30 value type:float64
如果我们只关心key
和value
的话没问题,如果我们关注其类型的时候那么问题来了,Age
字段结构体中明明定义的是int类型,但输出却是float类型的,百思不得其解,通过查找资料发现问题出在了json
里面,那就是Go语言中的json
包在序列化空接口存放的数字类型(整型、浮点型等)都会序列化成float64
类型。为了解决这个问题,我们就想到了反射。
使用反射
使用通过标签(tag)和反射通过遍历结构体字段的方式生成map,具体代码如下:
func main() {
user := User{Name: "小明", Age: 30}
userMap := make(map[string]interface{})
v := reflect.ValueOf(user)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
// 遍历结构体字段
// 指定tagName值为map中key;字段值为map中value
for i := 0; i < v.NumField(); i++ {
fi := t.Field(i)
if tagValue := fi.Tag.Get("json"); tagValue != "" {
userMap[tagValue] = v.Field(i).Interface()
}
}
for k, v := range userMap{
fmt.Printf("key:%v value:%v value type:%T\n", k, v, v)
}
}
通过执行上述代码输出如下:
key:name value:小明 value type:string
key:age value:30 value type:int64
对,没错,这才是我们想要的结果。
第三方库structs
第三种方法是使用第三方库https://github.com/fatih/structs
,不用我们再手动写。
安装:
go get github.com/fatih/structs
使用:
func main() {
user := User{Name: "小明", Age: 30}
userMap := structs.Map(user)
for k, v := range userMap{
fmt.Printf("key:%v value:%v value type:%T\n", k, v, v)
}
}
输出结果:
key:Name value:小明 value type:string
key:Age value:30 value type:int64
两行代码搞定,6的起飞。
总结
以上就是本文的全部内容了,主要介绍了Go中结构体转为map的实现三种方式,