顺晟科技
2021-06-16 10:27:20
583
我们通常用Go语言使用结构来存储我们的数据。例如,为了存储用户信息,我们可以定义以下结构:
//UserInfo用户信息
类型UserInfo结构{
名称字符串“json:”名称
Age int `json: ' age ' '
}
u1 :=UserInfo { Name : ' q1mi ',Age: 18}
假设你想把上面的u1转换成map[string]接口{},应该怎么做?
映射[字符串]接口的结构{}
JSON序列化方法
这不是很简单吗?我用JSON序列化u1,然后反序列化成map。首先,代码如下:
func main() {
u1 :=UserInfo { Name : ' q1mi ',Age: 18}
b,_ :=json。元帅(u1)
var m map[string]接口{}
_=json。解组(b,m)
对于k,v :=范围m{
fmt。Printf('key:%v值:%v\n ',k,v)
}
}
输出:
key:name value:q1mi
key:age年龄值:18
看起来没什么问题,其实这里有个“坑”。即数字类型(整数、浮点等。)以Go语言存储在json包中,将被序列化为float64类型。
也就是说,上面例子中的m['age']现在是底部的float64,而不是int。让我们验证一下:
func main() {
u1 :=UserInfo { Name : ' q1mi ',Age: 18}
b,_ :=json。元帅(u1)
var m map[string]接口{}
_=json。解组(b,m)
对于k,v :=范围m{
fmt。Printf('key:%v值:%v值类型:%T\n ',k,v,v)
}
}
输出:
key : name value : q1mi value type : string
key:age value:18值类型:float64
显然,有一种意想不到的行为,我们需要想办法避免它。
显示
如果你做不到,你需要自己去做。这里,地图是通过反射穿过结构场生成的。具体代码如下:
//ToMap结构转换为Map[string]接口{}
func ToMap(在接口{}中,标记名字符串)(映射[字符串]接口{},错误){
out :=make(map[string]interface { })
v :=反射。值(英寸)
如果v.Kind()==反映。Ptr {
v=v.Elem()
}
if v.Kind()!=reflect。结构体{//非结构体返回错误提示
返回零,fmt。Errorf('ToMap只接受结构或结构指针;得到%T ',v)
}
t :=v型()
//遍历结构字段
//将标记名值指定为映射中的键;字段值是地图中的值
对于I :=0;I . v . NumField();i {
fi :=t.Field(i)
如果tagValue :=fi。Tag.Get(标记名);tagValue!='' {
out[tagValue]=v.Field(i)。接口()
}
}
返回,零
}
验证:
m2,_ :=ToMap(u1,‘JSON’)
对于k,v :=范围m2{
fmt。Printf('key:%v值:%v值类型:%T\n ',k,v,v)
}
输出:
key : name value : q1mi value type : string
key:age value:18值类型:int
这次地图的类型是正确的。
第三方库结构
除了它自己的实现,Github还有现成的轮子,比如第三方库:https://github.com/fatih/structs.
它使用的自定义结构标记是结构:
//UserInfo用户信息
类型UserInfo结构{
名称字符串' json: '名称'结构: '名称' '
Age int `json:'age '结构: ' age ' '
}
用法很简单:
m3 :=结构。地图(u1)
对于k,v :=范围m3 {
fmt。Printf('key:%v值:%v值类型:%T\n ',k,v,v)
}
还有许多其他使用structs包的例子,所以您可以检查文档。但是,需要注意的是,这个库已经被作者设置为只读。
将嵌套结构转移到映射[字符串]接口{}
structures本身支持将嵌套结构转换为map[string]接口{}。结构嵌套时,会转化为map[string]interface{}嵌套map[string]interface{}的模式。
我们定义一组嵌套结构如下:
//UserInfo用户信息
类型UserInfo结构{
名称字符串' json: '名称'结构: '名称' '
Age int `json:'age '结构: ' age ' '
配置文件' json: '配置文件'结构: '配置文件' '
}
//配置文件配置信息
配置文件类型结构{
爱好字符串' json: '爱好'结构: '爱好' '
}
声明结构变量u1:
U13360=userinfo {name:' q1mi ',age: 18,profile: profile {'双色球' }}
第三方库结构
代码和上面的其实是一样的:
m3 :=结构。地图(u1)
对于k,v :=范围m3 {
fmt .Printf('key:%v值:%v值类型:%T\n ',k,v,v)
}
输出结果:
键:名称值: q1mi值类型:字符串
key:age年龄值:18值类型:int
键:简介值:地图[爱好:双色球]值类型:映射[字符串]接口{}
从结果来看最后嵌套字段轮廓是地图[字符串]接口{},属于地图嵌套地图。
使用反射转成单层地图
如果我们想把嵌套的结构体转换成一个单层地图该怎么做呢?
我们把上面反射的代码稍微修改一下就可以了:
//至放大器2将结构体转为单层地图
运算放大器2(在接口{}中,标记字符串)(映射[字符串]接口{},错误){
//当前函数只接收结构体类型
v :=反射。值(英寸)
如果五、种类()==反映Ptr { //结构体指针
v=v.Elem()
}
if v.Kind()!=反射.结构{
返回零fmt .Errorf('ToMap只接受结构或结构指针;得到“%T”,v)
}
out :=make(map[string]interface { })
队列:=make([]接口{},0,1)
queue=append(queue,in)
对于len(队列)0 {
v :=反射。值(队列[0])
如果五、种类()==反映Ptr { //结构体指针
v=v.Elem()
}
queue=queue[1:]
t :=v型()
对于I :=0;I . v . NumField();i {
vi :=v.Field(i)
如果六.Kind()==反映Ptr { //内嵌指针
vi=vi .Elem()
如果六.Kind()==反映Struct { //结构体
queue=append(queue,vi .Interface())
} else {
ti :=t.Field(i)
如果tagValue :=ti .标签。get(tag);tagValue!='' {
//存入地图
out[tagValue]=vi .接口()
}
}
破裂
}
如果六.Kind()==反映Struct { //内嵌结构体
queue=append(queue,vi .Interface())
破裂
}
//一般字段
ti :=t.Field(i)
如果tagValue :=ti .标签。get(tag);tagValue!='' {
//存入地图
out[tagValue]=vi .接口()
}
}
}
返回,零
}
测试一下:
m4,_ :=至amp 2(u1,‘JSON’)
对于k,v :=范围m4 {
fmt .Printf('key:%v值:%v值类型:%T\n ',k,v,v)
}
输出:
键:名称值: q1mi值类型:字符串
key:age年龄值:18值类型:int
键:爱好值:双色球值类型:string
这下我们就把嵌套的结构体转为单层的地图了,但是要注意这种场景下结构体和嵌套结构体的字段就需要避免重复。
28
1990-12
02
2022-09
29
2021-08
29
2021-08
28
2021-08
28
2021-08