18910140161

结构体转map[string]interface{}的若干方法

顺晟科技

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

这下我们就把嵌套的结构体转为单层的地图了,但是要注意这种场景下结构体和嵌套结构体的字段就需要避免重复。

相关文章
我们已经准备好了,你呢?
2024我们与您携手共赢,为您的企业形象保驾护航