golang 对不同结构体中数据进行相互转换的几种常用方法

常用的不同结构体中的数据相互转换的方法

1. 利用json包的marshal和unmarshal

要求:json标签的值必须一致
示例:

package main
import ("encoding/json""fmt"
)
type A struct {Name string `json:"name"`Age int `json:"age"`Gender string `json:"gender"`
}
type B struct {Name string `json:"name"`Age int `json:"age"`Weight string `json:"weight"`
}func main() {a:=A{Name:   "小可",Age:    121,Gender: "男",}var b BjsonBytes,_:=json.Marshal(a)err:=json.Unmarshal(jsonBytes,&b)if err!=nil{fmt.Println(err.Error())}else{fmt.Printf("%+v",b)}
}

输出:

{Name:小可 Age:121 Weight:}

2. 使用第三方包 copier 进行数据转换

要求:结构体的数据结构和字段名必须一致

go get github.com/jinzhu/copier

使用示例

import ("fmt""github.com/jinzhu/copier"
)func main() {a:=A{Name:   "小可",Age:    121,Gender: "男",}var b Berr := copier.Copy(&a, &b)if err!=nil{fmt.Println(err.Error())}else{fmt.Printf("%+v",b)}
}

对字段名相同,但是数据类型不同的字段,可以像这样额外添加option去转换

// time.Time 和 string 之间相互转换的方法
var CopierProtoOptions = copier.Option{IgnoreEmpty: true,DeepCopy:    true,Converters: []copier.TypeConverter{{SrcType: time.Time{},DstType: copier.String,Fn: func(src interface{}) (interface{}, error) {s, ok := src.(time.Time)if !ok {return nil, errors.New("src type :time.Time not matching")}return s.Format("2006-01-02 15:04:05"), nil},},{SrcType: copier.String,DstType: time.Time{},Fn: func(src interface{}) (interface{}, error) {s, ok := src.(string)if !ok {return nil, errors.New("src type :time.Time not matching")}tt, err := time.ParseInLocation(s, "2006-01-02 15:04:05", shanghai)return tt, err},},},
}

使用

type A struct {Name string Age intGender string BirthDay string 
}
type B struct {Name string Age intWeight stringBirthDay time.time
}func main() {a:=A{Name:   "小可",Age:    121,Gender: "男",BirthDay :"1997-05-08 11:20:11",}var b Berr := copier.CopyWithOption(&a, &b,CopierProtoOptions)if err!=nil{fmt.Println(err.Error())}else{fmt.Printf("%+v",b)}
}

3.对结构不同的结构体进行转换

举例有如下结构体,需要把DataRequest中的数据转换到ProtoRequest 中。特点是,ProtoRequest 中,定义了一个Query字段来继承*CommonQuery类型。

type CommonQuery struct {Id   intName string
}
type DataRequest struct {CommonQueryPage     int64 `json:"page"`PageSize int64 `json:"pageSize"`
}
type ProtoRequest struct {Query    *CommonQuery `json:"query"`Page     int64        `json:"page"`PageSize int64        `json:"pageSize"`
}

此时需要自定义一个方法,示例如下,大家可以参考下面的代码进行适当修改。

var shanghai, _ = time.LoadLocation("Asia/Shanghai")
func ConvertData(from interface{}, to interface{}) {var proxyField = "Query"fromValue := reflect.ValueOf(from)toValue := reflect.ValueOf(to)toType := reflect.TypeOf(to)// 获取From结构体的字段信息fromType := fromValue.Type().Elem()for i := 0; i < fromType.NumField(); i++ {// 获取字段名和字段值fieldName := fromType.Field(i).NamefieldValue := fromValue.Elem().FieldByName(fieldName)if fieldName != proxyField {_, exists := toType.Elem().FieldByName(fieldName)if exists {// 设置To结构体中相应字段的值toValue.Elem().FieldByName(fieldName).Set(fieldValue)}}}queryField, exists := toType.Elem().FieldByName(proxyField)if exists {var queryFieldTypeName string// 指针类型额外处理,拿到真实的数据类型if queryField.Type.Kind() == reflect.Ptr {queryFieldTypeName = queryField.Type.Elem().String()} else {queryFieldTypeName = queryField.Type.Kind().String()}//处理拿到的结构体类型如 utils.xxxx的类型,去掉utils.这部分if strings.Contains(queryFieldTypeName, ".") {queryFieldTypeName = strings.Split(queryFieldTypeName, ".")[1]}fromQueryValue := fromValue.Elem().FieldByName(queryFieldTypeName)if fromQueryValue.IsValid() && fromQueryValue.CanAddr() {toValue.Elem().FieldByName(proxyField).Set(fromQueryValue.Addr())}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/143204.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

前端开发 vs. 后端开发:编程之路的选择

文章目录 前端开发&#xff1a;用户界面的创造者1. HTML/CSS/JavaScript&#xff1a;2. 用户体验设计&#xff1a;3. 响应式设计&#xff1a;4. 前端框架&#xff1a; 后端开发&#xff1a;数据和逻辑的构建者1. 服务器端编程&#xff1a;2. 数据库&#xff1a;3. 安全性&#…

27、Flink 的SQL之SELECT (窗口函数)介绍及详细示例(3)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

STM32cubeIDE 更改Repository folder

使用STM32CubeIDE时&#xff0c;会调用STM32CubeMX&#xff0c;但是这两个软件下载的更新包都放在C:/user/目录下面&#xff0c;而且文件很大&#xff0c;用不了多久就会把C盘填满&#xff0c;所以刚开始安装的时候就要把更新目录更换掉。具体更换方法如下&#xff1a; Window…

浅谈软件测试面试一些常见的问题

一、简历及岗位匹配度 说到简历&#xff0c;其实这一点是很重要但又被很多职场小白忽视的问题。经常有人说我投了很多简历&#xff0c;但是没有公司给我打电话&#xff0c;怎么办&#xff1f; 首先&#xff0c;应该明白的一点&#xff1a;面对求职市场的激烈竞争性&#xff0…

docker系列(7) - Dockerfile

文章目录 7. Dockerfile7.1 Dockerfile介绍7.2 指令规则7.3 指令说明7.3.1 RUN命令的两种格式7.3.1 CMD命令覆盖问题7.3.2 ENTRYPOINT命令使用7.3.3 ENV的使用 7.4 构建tomcat Dockerfile案例7.4.1 准备原始文件7.4.2 编写Dockerfile7.4.3 构建镜像7.4.4 验证镜像 7.5 构建jdk基…

LeetCode 接雨水 木桶理论、dp预处理

原题链接&#xff1a; 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题面&#xff1a; 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a…

计算机里的神灵(SCIP)

计算机程序的构造和解释 我找到计算机里的神灵了&#xff0c;开心一刻 下面是从MIT官网下载的 SCIP求值器&#xff08;解释器&#xff09;的代码&#xff0c;这个官网是个宝藏库 还有其他视频课程和 SCIP的问题答案和可运行代码 链接&#xff1a;https://ocw.mit.edu/courses/6…

VS2022 编译protobuf , qt 使用

一、下载源码 protobuf: 同步 https://github.com/protocolbuffers/protobuf (gitee.com) 下载如v3.11.2 版本 二、下载CMake 三、编译 1、在1处选择源码目录下的cmake 目录&#xff1b;在2处选择一处空目录&#xff08;自己随便建&#xff09; 2、点击config&#xff0c;选择…

系统架构设计师-大数据

目录 一、大数据 1、大数据架构 2、大数据技术生态 3、Lambda架构 4、Kappa架构 5、Lambda架构与Kappa架构对比 一、大数据 1、大数据架构 大数据是指其大小或复杂性无法通过现有常用的软件工具&#xff0c;以合理的成本并在可接受的时限内对其进行捕获、管理和处理的数据集。…

【rhce考试时间是每年什么时候呢?】

RHCE9.0 新技术 公开课 10月11日&#xff0c;12日 感兴趣可留言 如果你是一个系统管理员&#xff0c;或者正朝着这个方向努力前进&#xff0c;那么你可能已经听过RHCE这个词。RHCE是Red Hat Certified Engineer的缩写&#xff0c;是全球公认的Linux系统工程师认证之一。通过获…

获取热门电影算法

功能#2&#xff1a;获取热门电影 为我们的“Netflix”项目实现“获取热门电影”功能。 我们将介绍以下内容 描述 解决方案 复杂性措施 时间复杂度 空间复杂度 描述# 现在&#xff0c;我们需要建立一个标准&#xff0c;以便将来自多个国家的顶级电影组合成一个单一的顶级电影…

postman访问新建项目报404

"status": 404 查看项目&#xff0c;发现启动类和代码执行部分没有在同一个包下&#xff0c;导致controller的访问没有注册到启动类下&#xff1b;

定义现代化实时数据仓库,SelectDB 全新产品形态全面发布

导读&#xff1a;9 月 25 日&#xff0c;2023 飞轮科技产品发布会在线上正式召开&#xff0c;本次产品发布会以 “新内核、新图景” 为主题&#xff0c;飞轮科技 CEO 马如悦全面解析了现代化数据仓库的演进趋势&#xff0c;宣布立足于多云之上的 SelectDB Cloud 云服务全面开放…

【设计模式】五、原型模式

文章目录 概述示例传统的方式的优缺点原型模式原理结构图-uml 类图 原型模式解决克隆羊问题的应用实例Sheep类实现clone()运行原型模式在 Spring 框架中源码分析 深入讨论-浅拷贝和深拷贝浅拷贝的介绍 小结 概述 示例 克隆羊问题 现在有一只羊 tom&#xff0c;姓名为: tom, 年…

【轮趣-科大讯飞】M260C 环形六麦测试 1 - 产品介绍与配置

原文发布在飞书上&#xff0c;想要的伙伴请联系我&#xff0c;懒得把飞书链接放这了

二十二、MySQL联合查询

1、基础概念 &#xff08;1&#xff09;语法&#xff1a; select …… from …… union [all] select …… from …… &#xff08;2&#xff09;理解&#xff1a; 所谓的联合查询&#xff0c;就是对多个条件查询结果进行联合处理&#xff0c;取其并集。 2、实际操作 &…

K8S:pod集群调度及相关操作

文章目录 一.pod集群调度概念1.调度约束( List-Watch组件)2.List-Watch的工作机制&#xff08;1&#xff09;List-Watch的工作机制流程&#xff08;2&#xff09;List-Watch的工作机制图示 3.调度的过程&#xff08;1&#xff09;调度的任务&#xff08;2&#xff09;调度选择p…

Java 设计模式——抽象工厂模式

目录 1.概念2.结构3.实现4.优缺点5.使用场景6.模式扩展7.JDK源码解析——Collection.iterator方法 1.概念 &#xff08;1&#xff09;Java 设计模式——工厂方法模式 中考虑的是一类产品的生产&#xff0c;如畜牧场只养动物、电视机厂只生产电视机等。这些工厂只生产同种类产品…

sqlmap tamper脚本编写

文章目录 tamper脚本是什么&#xff1f;指定tamper脚本运行sqlmap安全狗绕过tamper脚本 tamper脚本是什么&#xff1f; SQLMap 是一款SQL注入神器&#xff0c;可以通过tamper 对注入payload 进行编码和变形&#xff0c;以达到绕过某些限制的目的。但是有些时候&#xff0c;SQLM…

Qt创建线程(使用moveToThread方法创建子线程)

1.moveTothread方法: &#xff08;1&#xff09;要使用moveToThread方法必须继承与QObject类 &#xff08;2&#xff09;创建任务对象时不能指定父对象 例子&#xff1a; MyWork* work new MyWork(this); // error MyWork* work new MyWork; // ok &#xff08;3&#…