今天遇到一个问题,想把pb转成map,如下所示:
func TestUnmarshalPbTojson(t *testing.T) {
rq:=&UserInfo{Status: "error",Amount: "1.11"}
//m:=map[string]interface{}{}
err:=json.Valid([]byte(rq.String())) //not valid,不能够直接由该字符串转成map
t.Errorf("err:%v,json str:%v",err,rq.String())
}
所以很无奈,就不得不选择了稍微繁琐一点的方式(使用go的反射获得pb结构体的field,使用for循环将field转成map),如下代码所示:
func TestUnmarshalPbTojson(t *testing.T) {
rq:=&userInfo{Status: "error",Amount: "1.11"}
//m:=map[string]interface{}{}
err:=json.Valid([]byte(rq.String()))
t.Errorf("err:%v,json str:%v",err,rq.String())
pb2map(rq,t)
}
func pb2map(rp interface{}, t *testing.T) {
m:=make(map[string]string)
vals:=reflect.ValueOf(rp).Elem()
for i:=0;i<vals.NumField();i++{
valueField:=vals.Field(i)
typeField:=vals.Type().Field(i)
f:=valueField.Interface()
val:=reflect.ValueOf(f) //由于遍历的时候,会遍历到私有变量,但私有变量的值不可以直接取得,会报pa
m[typeField.Name]=val.String()
}
t.Logf("pb2map,origin:%v,dst:%v",rp,vals)
}
因为私有变量不可以直接使用反射获取到内部的value,不得不进一步查询相关api,最后发现了Value.CanInterface(),通过调用这个方法,go会内部校验该变量是否为私有变量,是否可被导出,从而成功解决了我的问题,最终代码如下所示:
func pb2map(rp interface{}, t *testing.T) {
m:=make(map[string]string)
vals:=reflect.ValueOf(rp).Elem()
for i:=0;i<vals.NumField();i++{
valueField:=vals.Field(i)
typeField:=vals.Type().Field(i)
if valueField.CanInterface(){
f:=valueField.Interface()
val:=reflect.ValueOf(f)
t.Logf("pb2map,name:%v,val:%v,tagname:%v",typeField.Name,val.String(),typeField.Tag.Get("json"))
m[typeField.Tag.Get("json")]=val.String() //可以根据需要取具体的tag,做相应的处理即可
}
}
t.Logf("pb2map,origin:%v,dst:%v",rp,vals)
}
也算是比较好的一天吧,解决了问题,也新学了api的使用,也算是对go的理解更加加深了吧。