当前位置: 首页 > article >正文

golang结构体转map

结构体转map

借助反射和标签实现结构体转map

代码

func StructToMap(data any, tagName string) (mp map[string]any, err error) {
	// 初始化一个空的 map 用于存储结果
	mp = make(map[string]any)

	// 使用 reflect 包获取传入数据的反射值
	v := reflect.ValueOf(data)

	// 检查传入的数据是否为结构体类型
	if v.Kind() != reflect.Struct {
		// 如果不是结构体,则返回错误
		err = errors.New("传入转化的对象非结构体")
		return
	}

	// 打印结构体类型信息,可用于调试
	fmt.Println(v.Type())

	// 遍历结构体的每个字段
	for i := 0; i < v.NumField(); i++ {
		// 获取当前字段的反射值
		val := v.Field(i)
		// 获取当前字段的类型信息,并从指定标签中取得 tag 值
		tag := v.Type().Field(i).Tag.Get(tagName)

		// 如果 tag 为空或者等于 "-", 则跳过此字段
		if tag == "" || tag == "-" {
			continue
		}

		// 特别处理指针类型的字段
		if val.Kind() == reflect.Ptr {
			// 如果指针是 nil, 跳过此字段
			if val.IsNil() {
				continue
			}
			// 否则,解引用指针并将其值存入 map 中
			mp[tag] = val.Elem().Interface()
			continue
		}

		// 对于非指针类型的字段,直接将字段值存入 map 中
		mp[tag] = val.Interface()
	}

	// 返回生成的 map 和 nil 错误表示成功
	return
}

工作流程

  1. 初始化结果容器
    • 创建一个空的 map[string]any 来存储转换后的键值对。
  2. 获取传入参数的反射值
    • 使用 reflect.ValueOf(data) 获取传入结构体的反射值 v
  3. 验证输入是否为结构体
    • 检查 v.Kind() 是否等于 reflect.Struct。如果不是,则抛出错误并终止函数执行。
  4. 遍历结构体字段
    • 使用 v.NumField() 方法得到结构体字段的数量,并使用 for 循环迭代这些字段。
  5. 处理每个字段
    • 对于每一个字段,获取其反射值 val 和对应的类型信息。
    • 使用 v.Type().Field(i).Tag.Get(tagName) 获取指定标签名的 tag 值,这通常用于序列化配置(如 JSON, XML 标签)。
    • 如果 tag 是空字符串或者特定标记 -,则跳过该字段,不加入到最终的 map 中。
  6. 处理指针类型字段
    • 当字段是 reflect.Ptr 类型时,额外检查它是否为 nil。如果是非 nil 的指针,解引用指针以获取实际值,并将该值存入 map 中。
  7. 添加字段到 map
    • 将字段值(直接值或指针指向的值)和对应的 tag 名称作为键值对添加到 map 中。
  8. 返回结果
    • 最后,函数返回填充好的 map 和任何可能发生的错误。

测试

func TestStructToMap(t *testing.T) {
	type successTestStruct struct {
		String string `tag-string:"string"`
		Int    int    `tag-number:"int"`
		Bool   bool   `tag-bool:"bool"`
	}
	var test = successTestStruct{
		String: "测试",
		Int:    10086,
		Bool:   false,
	}
	var testMap map[string]any
	var err error
	if testMap, err = struct_to_map.StructToMap(test, "tag-string"); testMap["string"] != "测试" {
		fmt.Println(err)
		t.Fatal("字符串结构体转map失败")
	} else {
		fmt.Println(testMap)
		t.Log("字符串结构体转map成功")
	}
	if testMap, err = struct_to_map.StructToMap(test, "tag-number"); testMap["int"] != 10086 {
		fmt.Println(err)
		t.Fatal("整型结构体转map失败")
	} else {
		fmt.Println(testMap)
		t.Log("整型结构体转map成功")
	}
	if testMap, err = struct_to_map.StructToMap(test, "tag-bool"); testMap["bool"] != false {
		fmt.Println(err)
		t.Fatal("布尔结构体转map失败")
	} else {
		fmt.Println(testMap)
		t.Log("布尔结构体转map成功")
	}
}

测试结果

=== RUN   TestStructToMap
map[string:测试]
    StructToMap_test.go:28: 字符串结构体转map成功
map[int:10086]
    StructToMap_test.go:35: 整型结构体转map成功
map[bool:false]
    StructToMap_test.go:42: 布尔结构体转map成功
--- PASS: TestStructToMap (0.00s)
PASS

http://www.kler.cn/a/443983.html

相关文章:

  • dify.ai和fastgpt,各有什么优缺点,有什么区别
  • 【计算机视觉基础CV】03-深度学习图像分类实战:鲜花数据集加载与预处理详解
  • 使用Python脚本进行编写批量根据源IP进行查询的语句用于态势感知攻击行为的搜索
  • 省略内容在句子中间
  • 安装配置Ubuntu 22.04
  • Binder 大小
  • 线性规划中的几种逻辑表达式
  • C#核心(18)面向对象多态vob
  • LabVIEW中的“Synchronize with Other Application Instances“
  • uniapp blob格式转换为video .mp4文件使用ffmpeg工具
  • DePIN潜力项目Spheron解读:激活闲置硬件,赋能Web3与AI
  • rust使用log与env_logger两个crate实现同时向控制台和文件输出日志。并在隔日自动创建新日志文件。
  • IEC 101/104 中为什么我们需要单点和双点信号
  • 01、NodeJS学习笔记,第一节:Node.js初识与内置模块
  • 如果 MySQL 的自增 ID 用完了,怎么解决?
  • C语言学习day24:DLL函数导出详情
  • leetcode 881.救生艇
  • R语言的字符串操作
  • APO v1.1.0 更新:大模型根因分析支持深入分析;优化数据筛选功能;内置 NGINX 日志分析看板
  • 小米自研系统Vela全面开源:开启物联网新时代的技术革新之旅