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缓冲channel和非缓冲channel的区别说明
Apr 25 Golang
Golang 正则匹配效率详解
Apr 25 Golang
go语言中json数据的读取和写出操作
Apr 28 Golang
golang 生成对应的数据表struct定义操作
Apr 28 Golang
Go语言中break label与goto label的区别
Apr 28 Golang
基于Go Int转string几种方式性能测试
Apr 28 Golang
golang 实现Location跳转方式
May 02 Golang
Golang二维数组的使用方式
May 28 Golang
浅谈GO中的Channel以及死锁的造成
Mar 18 Golang
简单聊聊Golang中defer预计算参数
Mar 25 Golang
Golang 对es的操作实例
Apr 20 Golang
Golang日志包的使用
Apr 20 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无限分类代码,支持数组格式化、直接输出菜单两种方式
2011/05/18 PHP
php实现改变图片直接打开为下载的方法
2015/04/14 PHP
php实现模拟登陆方正教务系统抓取课表
2015/05/19 PHP
php简单生成随机数的方法
2015/07/30 PHP
详细解读php的命名空间(二)
2018/02/21 PHP
js String对象中常用方法小结(字符串操作)
2012/01/27 Javascript
JavaScript控制Session操作方法
2013/01/17 Javascript
setTimeout()与setInterval()方法区别介绍
2013/12/24 Javascript
js实现简单的左右两边固定广告效果实例
2015/04/10 Javascript
HTML5实现留言和回复页面样式
2015/07/22 Javascript
jQuery Validation Plugin验证插件手动验证
2016/01/26 Javascript
Jquery轮播效果实现过程解析
2016/03/30 Javascript
jquery实现无刷新验证码的简单实例
2016/05/19 Javascript
ExtJs的Ext.Ajax.request实现waitMsg等待提示效果
2017/06/14 Javascript
nodejs中sleep功能实现暂停几秒的方法
2017/07/12 NodeJs
nodejs基于mssql模块连接sqlserver数据库的简单封装操作示例
2018/01/05 NodeJs
Vue 中mixin 的用法详解
2018/04/23 Javascript
Angular实现svg和png图片下载实现
2019/05/05 Javascript
vue 实现搜索的结果页面支持全选与取消全选功能
2019/05/10 Javascript
在Vue中获取自定义属性方法:data-id的实例
2020/09/09 Javascript
[57:22]完美世界DOTA2联赛PWL S2 FTD vs PXG 第二场 11.27
2020/12/01 DOTA
详解Python 2.6 升级至 Python 2.7 的实践心得
2017/04/27 Python
使用matplotlib画散点图的方法
2018/05/25 Python
Python合并同一个文件夹下所有PDF文件的方法
2019/03/11 Python
django-rest-swagger的优化使用方法
2019/08/29 Python
Pytorch 扩展Tensor维度、压缩Tensor维度的方法
2020/09/09 Python
考试不及格检讨书
2014/01/09 职场文书
大学运动会入场词
2014/02/22 职场文书
党支部对照检查材料
2014/08/25 职场文书
小学体育组工作总结2015
2015/07/21 职场文书
《怀念母亲》教学反思
2016/02/19 职场文书
Html5生成验证码的示例代码
2021/05/10 Javascript
Python爬虫基础之初次使用scrapy爬虫实例
2021/06/26 Python
python脚本框架webpy模板赋值实现
2021/11/20 Python
windows11怎么查看自己安装的版本号? win11版本号的查看方法
2021/11/21 数码科技
代码复现python目标检测yolo3详解预测
2022/05/06 Python