golang 实现两个结构体复制字段


Posted in Golang onApril 28, 2021

实际工作中可能会有这样的场景:

两个结构体(可能类型一样), 字段名和类型都一样, 想复制一个结构体的全部或者其中某几个字段的值到另一个(即merge操作),

自然想到可以用反射实现

package main
import "fmt"
import "reflect"
// 用b的所有字段覆盖a的
// 如果fields不为空, 表示用b的特定字段覆盖a的
// a应该为结构体指针
func CopyFields(a interface{}, b interface{}, fields ...string) (err error) {
	at := reflect.TypeOf(a)
	av := reflect.ValueOf(a)
	bt := reflect.TypeOf(b)
	bv := reflect.ValueOf(b)
	// 简单判断下
	if at.Kind() != reflect.Ptr {
		err = fmt.Errorf("a must be a struct pointer")
		return
	}
	av = reflect.ValueOf(av.Interface())
	// 要复制哪些字段
	_fields := make([]string, 0)
	if len(fields) > 0 {
		_fields = fields
	} else {
		for i := 0; i < bv.NumField(); i++ {
			_fields = append(_fields, bt.Field(i).Name)
		}
	}
	if len(_fields) == 0 {
		fmt.Println("no fields to copy")
		return
	}
	// 复制
	for i := 0; i < len(_fields); i++ {
		name := _fields[i]
		f := av.Elem().FieldByName(name)
		bValue := bv.FieldByName(name)
		// a中有同名的字段并且类型一致才复制
		if f.IsValid() && f.Kind() == bValue.Kind() {
			f.Set(bValue)
		} else {
			fmt.Printf("no such field or different kind, fieldName: %s\n", name)
		}
	}
	return
}
type S1 struct {
    Name string
    Age int
}
type S2 struct {
    Name string
    Age int32
}
func main() {
    s1 := S1{"hello", 22}
    s2 := S2{"world", 33}
    fmt.Println(s1, s2)
    CopyFields(&s1, s2)
    fmt.Println(s1, s2)
}

上述例子输出为:

{hello 22} {world 33}

no such field or different kind, fieldName: Age

{world 22} {world 33}

可见s2的Name字段值已经成功被覆盖.

而s2中Age字段和s1中Age字段类型不一样, 会忽略.

其实上面的还可以优化, 毕竟int32和int还是可以认为是"一样"的类型的,

不过思路就是这样.

补充:golang使用反射将一个结构体的数据直接复制到另一个结构体中(通过相同字段)

看代码吧~

package main
import (
	"fmt"
	"reflect"
)
type A struct {
	Name   string
	Gender string
	Age    int
}
type B struct {
	Name   string
	Gender string
}
//binding type interface 要修改的结构体
//value type interace 有数据的结构体
func structAssign(binding interface{}, value interface{}) {
	bVal := reflect.ValueOf(binding).Elem() //获取reflect.Type类型
	vVal := reflect.ValueOf(value).Elem()   //获取reflect.Type类型
	vTypeOfT := vVal.Type()
	for i := 0; i < vVal.NumField(); i++ {
		// 在要修改的结构体中查询有数据结构体中相同属性的字段,有则修改其值
		name := vTypeOfT.Field(i).Name
		if ok := bVal.FieldByName(name).IsValid(); ok {
			bVal.FieldByName(name).Set(reflect.ValueOf(vVal.Field(i).Interface()))
		}
	}
}
func main() {
	as := A{}
	bs := B{Name: "wfy", Gender: "男"}
	fmt.Println(as)
	structAssign(&as, &bs)
	fmt.Println(as)
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方,望不吝赐教。

Golang 相关文章推荐
go语言map与string的相互转换的实现
Apr 07 Golang
Golang 正则匹配效率详解
Apr 25 Golang
golang中切片copy复制和等号复制的区别介绍
Apr 27 Golang
解决go在函数退出后子协程的退出问题
Apr 30 Golang
对Golang中的FORM相关字段理解
May 02 Golang
Golang全局变量加锁的问题解决
May 08 Golang
go语言基础 seek光标位置os包的使用
May 09 Golang
Golang实现AES对称加密的过程详解
May 20 Golang
golang 实用库gotable的具体使用
Jul 01 Golang
手把手教你导入Go语言第三方库
Aug 04 Golang
Go语言基础切片的创建及初始化示例详解
Nov 17 Golang
Golang bufio详细讲解
Apr 21 Golang
go结构体嵌套的切片数组操作
Apr 28 #Golang
golang json数组拼接的实例
Apr 28 #Golang
golang 实现对Map进行键值自定义排序
Apr 28 #Golang
go语言中json数据的读取和写出操作
Apr 28 #Golang
golang 实现菜单树的生成方式
Apr 28 #Golang
golang通过递归遍历生成树状结构的操作
Apr 28 #Golang
goland 恢复已更改文件的操作
You might like
php file_exists 检查文件或目录是否存在的函数
2010/05/10 PHP
php实现上传图片保存到数据库的方法
2015/02/11 PHP
golang、python、php、c++、c、java、Nodejs性能对比
2017/03/12 NodeJs
Laravel 添加多语言提示信息的方法
2019/09/29 PHP
Jquery 滑入滑出效果实现代码
2010/03/27 Javascript
jquery.validate使用攻略 第二部
2010/07/01 Javascript
jquery清空表单数据示例分享
2014/02/13 Javascript
瀑布流布局代码一例
2014/04/11 Javascript
JavaScript比较两个对象是否相等的方法
2015/02/06 Javascript
浅谈Javascript的静态属性和原型属性
2015/05/07 Javascript
jquery实现的伪分页效果代码
2015/10/29 Javascript
Zero Clipboard实现浏览器复制到剪贴板的方法(多个复制按钮)
2016/03/24 Javascript
node.js实现端口转发
2016/04/14 Javascript
JS 60秒后重新发送验证码的实例讲解
2017/07/26 Javascript
深入浅析JavaScript中的in关键字和for-in循环
2020/04/20 Javascript
微信小程序学习总结(三)条件、模板、文件引用实例分析
2020/06/04 Javascript
SublimeText 2编译python出错的解决方法(The system cannot find the file specified)
2013/11/27 Python
在MAC上搭建python数据分析开发环境
2016/01/26 Python
Python3 处理JSON的实例详解
2017/10/29 Python
pandas按若干个列的组合条件筛选数据的方法
2018/04/11 Python
python matplotlib绘图,修改坐标轴刻度为文字的实例
2018/05/25 Python
使用python脚本实现查询火车票工具
2018/07/19 Python
详解使用python绘制混淆矩阵(confusion_matrix)
2019/07/14 Python
在linux系统下安装python librtmp包的实现方法
2019/07/22 Python
Python any()函数的使用方法
2019/10/28 Python
Python如何实现动态数组
2019/11/02 Python
Python pip配置国内源的方法
2020/02/14 Python
Python run()函数和start()函数的比较和差别介绍
2020/05/03 Python
python实现企业微信定时发送文本消息的实例代码
2020/11/25 Python
初中生物教学反思
2014/01/10 职场文书
大学生评语大全
2014/04/18 职场文书
2014年终个人工作总结
2014/11/07 职场文书
故宫的导游词
2015/01/31 职场文书
求职信内容一般写什么?
2015/03/20 职场文书
乡镇团委工作总结2015
2015/05/26 职场文书
python基于tkinter制作无损音乐下载工具
2021/03/29 Python