资讯 更多 >>
自古以来,反射也是兵家必争之地-当...
诺阿:希望霍福德能夺冠 他证明了...
全球焦点!“吴谢宇弑母案”将公开...
天天视讯!中国各大军校录取分数线_...
windows10开机密码如何关闭_win10开...
阿尔法·罗密欧Giulia SWB Zagato...
嫩玉米能钓到什么鱼(嫩玉米钓鲤鱼...
【报资讯】凯格精机董秘回复:公司...
前沿科技剧透未来
国家统计局:4月工业企业利润降幅继...
动态更多 >>
报告:长三角专精特新“小巨人”企...
关于新学期的内容的手抄报_关于新学...
世界报道:人生苦短,好好爱自己,比...
环球短讯!方舆数字底座”发布 探...
访业界专家:组建国家数据局,迎数...
求职者速看!朱村街最新岗位招聘信...
国乒爆冷被横扫!孙颖莎三金梦碎,...
每日视讯:苏丹首都圈武装冲突降温...
京沪高铁网上中签结果_京沪高铁网上订票
今日降雨降温,最高22℃!北京海淀...
美籍酿酒师在崇礼:中国是第二故乡...
河南项城报告2名疑似新冠肺炎病例 ...
浙江绍兴确诊病例首次零新增 上虞...
广西东兴实行全员居家隔离 启动口...
新疆全方位推进乡村振兴 “富春山...
云南瑞丽市主城区全员核酸检测结果...
内蒙古满洲里累计治愈出院本土确诊...
孙海洋夫妻驱车山东阳谷:还在为孙...
大国工匠追梦“玉米强国”40载:用...
让南海“海洋热带雨林”斑斓多彩
专题报道 
当前位置: > 资讯 >
 
自古以来,反射也是兵家必争之地-当前速看
来源:博客园     时间:2023-05-27 22:28:54

这几天收到一个战术性需求,将一大坨字段序列化为特定格式的字符串。


(相关资料图)

大概是下表这样:

序号字段名描述是否必填
0logVersion日志版本
1productName产品
2serviceName服务
...
...
...
25extend3扩展字段3
26extend4扩展字段3
27extend5扩展字段3
checklist-client com.CommonApiController uploadImage 2017-12-27 10:35:08 378 1.0 null null 192.168.35.12 EBJ4945 null null ylKLPAvAsoaWRnqGZhZ6xqZ6hkYxSrVKsQDOSOpwXgAAAA== 0 91 null null 0 202226d4-255f-891c-b627-9efc28ef366b 0 010 -1 null null null null null null

控制点1:必填字段少,若可选字段无值,该字段序列化为“null”;

控制点2:序列化时只显示字段值(有序),字段之间用空格区分。

这不就是自定义序列化 且设置序列化默认值?

真要我挨个字段填充,我眼睛都要对花, 而且很容易漏掉字段。

// 伪代码如下:  b := bytes.Buffer{}b.WriteString("P1")b.WriteString(" ")b.WriteString("null")b.WriteString(" ")b.WriteString("null")b.WriteString(" ")b.WriteString("A")  ...  b.WriteString(" ")  b.WriteString("null")  log.Info(b.String())

根据"必填字段极少,可选字段默认设为null字符串"的背景,我开始自定义序列化器:

使用struct来定义结构,便于对必填字段赋值 (这个行为肉眼友好)将struct的[字段:字段值]转换为排好序的map键值对对排好序的map键值对无脑序列化

将结构体转换为 map, 这个行为涉及元类型的变动,联想到反射。

自古以来,反射也是兵家必争之地, 于是首次操刀golang的反射特性。

思路和伪代码很明确,实操时还是有2点障碍:

golang付map做for循环,键值对的出现是随机的。函数传参注意传指针值,而不要传结构体值。

关于第一个问题,利用网上的[提取key放在slice里面,再根据key的排序取map值]的思路是想当然了。我们的key是字符串,sort.Strings()之后依旧不是自己的预期(预期是按照struct字段出现的先后顺序)。

所以对map做for循环时,能拿到与struct字段出现顺序一致的键值对就是关键。

取巧:

我们利用反射struct时的字段顺序,定义了一个按照struct字段出现顺序为键的map[int]string,这样sort.Ints(keys)排序之后,for map时依旧是我们预期的键值对顺序。

func constructFixedMap(body interface{}) map[int]string {      typ := reflect.TypeOf(body)  //TypeOf返回目标数据类型   val := reflect.ValueOf(body)  //ValueOf返回目标数据的的值   if typ.Kind() != reflect.Pointer {   fmt.Println("expect pointer")   return nil   }   typ = typ.Elem() // 返回指针所指向的原值   val = val.Elem()   mp := make(map[int]string, 20)   for i := 0; i < typ.NumField(); i++ {    if typ.Field(i).Type.Kind().String() == "string" {   if val.Field(i).String() == "" {    // 可选字段,在反射时被修改   mp[i] = "null"   } else {   mp[i] = val.Field(i).String()     // 必填字段,保持不变   }   } else {   if val.Field(i).CanInt() {   mp[i] = strconv.FormatInt(val.Field(i).Int(), 10)   } else {   mp[i] = "null"   }   }   }   return mp}
记忆点回顾golang反射在自定义序列化器中的运用。对map做for循环,键值对的出现是随机的; 对keys排序,根据排序的keys再取map键值对要随机应变。

关键词:

上一条:诺阿:希望霍福德能夺冠 他证明了拥有老将的重要性-今日观点 下一条:最后一页