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

news/2024/11/30 1:33:27/

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

    • 常用的不同结构体中的数据相互转换的方法
      • 1. 利用json包的marshal和unmarshal
      • 2. 使用第三方包 copier 进行数据转换
      • 3.对结构不同的结构体进行转换

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

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.ppmy.cn/news/1132385.html

相关文章

idea没有maven工具栏解决方法

背景&#xff1a;接手的一些旧项目&#xff0c;有pom文件&#xff0c;但是用idea打开的时候&#xff0c;没有认为是maven文件&#xff0c;所以没有maven工具栏&#xff0c;不能进行重新加载pom文件中的依赖。 解决方法&#xff1a;选中pom.xml文件&#xff0c;右键 选择添加为…

Python3数据科学包系列(一):数据分析实战

认识下数据科学中数据处理基础包: (1)NumPy 俗话说: 要学会跑需先学会走 (1)数据分析基础认知:NumPy是,Numerical Python的简称,它是目前Python数值计算中最为重要的基础包,大多数计算包提供了基于NumPy的科学函数功能;将NumPy的数值对象作为数据交换的通用语 NumPy通常用于处…

Unity 一些常用特性收集

常用的类的特性 特性效果[Serializable]可序列化&#xff0c;作为一个子属性显示在Inspector面板[RequireComponent(typeof(CoomponnetName))]该类挂载的游戏物体&#xff0c;需要要有对应的组件[DisallowMultipleComponent]不允许挂载多个该类或其子类[ExecuteInEditMode]允许…

点亮一个LED+LED闪烁+LED流水灯——“51单片机”

各位CSDN的uu们好呀&#xff0c;这是小雅兰的最新专栏噢&#xff0c;最近小雅兰学习了51单片机的知识&#xff0c;所以就想迫不及待地分享出来呢&#xff01;&#xff01;&#xff01;下面&#xff0c;让我们进入51单片机的世界吧&#xff01;&#xff01;&#xff01; 点亮一个…

spring boot项目 mvn test 和 mvn clean install 和 mvn test-compile 识别不到测试类无法运行单元测试

测试类使用了junit4&#xff0c; spring boot 版本的test 框架自带的是junit5&#xff0c;不兼容。 按照spring boot 对应的版本的junit框架&#xff0c;修改测试类&#xff0c;比如我就修改了junit5。按照&#xff1a; https://docs.spring.io/spring-boot/docs/2.6.3/refere…

12、Kubernetes中KubeProxy实现之iptables和ipvs

目录 一、概述 二、iptables 代理模式 三、iptables案例分析 四、ipvs案例分析 一、概述 iptables和ipvs其实都是依赖的一个共同的Linux内核模块&#xff1a;Netfilter。Netfilter是Linux 2.4.x引入的一个子系统&#xff0c;它作为一个通用的、抽象的框架&#xff0c;提供…

RSS订阅

RSS订阅是一种内容聚合的工具&#xff0c;它可以帮助你聚合、分类、整理日常大量信息。以下是使用RSS订阅的一些好处&#xff1a; 获取更新信息&#xff1a;当你订阅了某个网站或者主题&#xff0c;每当有新的内容更新&#xff0c;你都会第一时间收到通知。提高阅读效率&#…

阿里云ECS服务器无法发送邮件问题解决方案

这篇文章分享一下自己把项目部署在阿里云ECS上之后&#xff0c;登录邮件提醒时的邮件发送失败问题&#xff0c;无法连接发送邮箱的服务器。 博主使用的springboot提供的发送邮件服务&#xff0c;如下所示&#xff0c;为了实现异步的效果&#xff0c;新开了一个线程来发送邮件。…