首页 > 其他分享 >自古以来,反射也是兵家必争之地

自古以来,反射也是兵家必争之地

时间:2023-05-27 21:58:27浏览次数:39  
标签:兵家必争之地 自古以来 序列化 WriteString val map 键值 反射 null

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

大概是下表这样:

序号 字段名 描述 是否必填
0 logVersion 日志版本
1 productName 产品
2 serviceName 服务
...
...
...
25 extend3 扩展字段3
26 extend4 扩展字段3
27 extend5 扩展字段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字符串"的背景,我开始自定义序列化器:

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

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

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

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

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

关于第一个问题,利用网上的[提取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键值对要随机应变。

标签:兵家必争之地,自古以来,序列化,WriteString,val,map,键值,反射,null
From: https://www.cnblogs.com/JulianHuang/p/17437421.html

相关文章

  • 字节码增强版的反射, jdk是操作读取我们的字节码文件
    javasissit生成类库 类池子创建,类池制造类,然后制造方法,将方法加到类里面,然后生成class, 再到jvm内存中获取哦  反射获取所有的方法      ......
  • PCI5565反射内存
    PCI5565反射内存具备多项特性,使其成为高效的数据传输解决方案。首先,它是一种高速的网络,支持nGbaud数据传输,可以快速处理大量数据。其次,PCI5565反射内存易于使用,无需过多的操作步骤即可实现数据传输。另外,它的可扩展性非常强,可方便地升级到其他形式。与操作系统和处理器无关的特性也......
  • 反射之PropertyDescriptor
    反射可以为对象的私有属性赋值java提供了一个类PropertyDescriptor通过这个类可以为对象的属性赋值需要进行赋值的对象@DatapublicclassTestEntity{privateStringusername;privateStringpassword;privateIntegerage;privateBooleansex;p......
  • 反射
    反射的概述(JavaReflection)Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包......
  • PHP 反射机制打印对象
    1<?php2/**34echoObj::new('Redis');5echoObj::new('Redis')->method('set')?->isPublic();67*/89classObjextendsReflectionClass10{11publicstaticfunctionstd(?array$attrs=null)1......
  • C# 反射的定义和应用场景
     1什么是反射首先要复习一下C#的编译过程,可以解释为下图其中dll/exe中,包括元数据(metadata)和IL(中间语言IntermediateLanguage)另外还出现的其他名词:CLR(公共语言运行时,CommonLanguageRuntime)和JIT(实时编译器JustinTime)总结:一个运行的程序查看本身的元数据或......
  • 【Java基础】万字长文深入理解Java反射机制
    大家好,我是程序员青戈,一个被Bug耽误了才艺的程序员......
  • java反射代码案例
    反射案例代码点击查看代码packagecom.bh.zoo;publicclassWolfextendsAnimal{publicStringname;publicStringcolor;protectedStringblood;privateintage;publicvoideat(){System.out.println("狼吃肉");}public......
  • java 反射:类和属性是否有注解
    booleanisAnnotationPresent(Class<?extendsAnnotation>annotationClass)元素上是否包含指定类型的注解,存在则返回true,否则返回false<AextendsAnnotation>AgetAnnotation(Class<A>annotationClass)获取元素上指定的注解,如果元素没有该注解返回null<AextendsAnn......
  • 2023.5.21学习内容 多态、接口、泛型、反射
    下午1.了解CSS响应式布局和兼容性问题2.浏览IDEA使用手册并修改Maven仓库设置3.复习强化JavaSE的多态、接口、泛型、反射知识importorg.junit.Test;importtest.Hello;importjava.lang.reflect.Field;importjava.util.ArrayList;importjava.util.LinkedList;import......