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 相关文章推荐
golang 在windows中设置环境变量的操作
Apr 29 Golang
Go语言 go程释放操作(退出/销毁)
Apr 30 Golang
go设置多个GOPATH的方式
May 05 Golang
Golang: 内建容器的用法
May 05 Golang
解决golang 关于全局变量的坑
May 06 Golang
基于Golang 高并发问题的解决方案
May 08 Golang
入门学习Go的基本语法
Jul 07 Golang
Go Plugins插件的实现方式
Aug 07 Golang
Golang使用Panic与Recover进行错误捕获
Mar 22 Golang
GoFrame框架数据校验之校验结果Error接口对象
Jun 21 Golang
Go中使用gjson来操作JSON数据的实现
Aug 14 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生成制作验证码代码详解(推荐)
2016/06/12 PHP
javascript基础的动画教程,直观易懂
2007/01/10 Javascript
jQuery live
2009/05/15 Javascript
JavaScript 10件让人费解的事情
2010/02/15 Javascript
某人初学javascript的时候写的学习笔记
2010/12/30 Javascript
正负小数点后两位浮点数实现原理及代码
2013/09/06 Javascript
javascript获取隐藏元素(display:none)的高度和宽度的方法
2014/06/06 Javascript
javascript递归回溯法解八皇后问题
2015/04/22 Javascript
仅9张思维导图帮你轻松学习Javascript 就这么简单
2016/06/01 Javascript
JS添加删除DIV的简单实例
2016/07/08 Javascript
浅谈Angular中ngModel的$render
2016/10/24 Javascript
文件上传的几个示例分享【推荐】
2016/12/16 Javascript
Vuejs实现带样式的单文件组件新方法
2017/05/02 Javascript
JavaScript数据结构之单链表和循环链表
2017/11/28 Javascript
vue 之 css module的使用方法
2018/12/04 Javascript
JavaScript实现美化滑块效果
2019/05/17 Javascript
JointJS JavaScript流程图绘制框架解析
2019/08/15 Javascript
js new Date()实例测试
2019/10/31 Javascript
基于javascript实现日历功能原理及代码实例
2020/05/07 Javascript
vue+axios全局添加请求头和参数操作
2020/07/24 Javascript
JavaScript 实现轮播图特效的示例
2020/11/05 Javascript
[02:30]DOTA2英雄基础教程 暗影恶魔
2013/12/17 DOTA
python网络编程示例(客户端与服务端)
2014/04/24 Python
wxpython 最小化到托盘与欢迎图片的实现方法
2014/06/09 Python
一个小示例告诉你Python语言的优雅之处
2014/07/04 Python
用Python解决计数原理问题的方法
2016/08/04 Python
你应该知道的python列表去重方法
2017/01/17 Python
Python列表和元组的定义与使用操作示例
2017/07/26 Python
利用python将图片转换成excel文档格式
2017/12/30 Python
pandas如何处理缺失值
2019/07/31 Python
Python大数据之从网页上爬取数据的方法详解
2019/11/16 Python
nginx+uwsgi+django环境搭建的方法步骤
2019/11/25 Python
如何使用python传入不确定个数参数
2020/02/18 Python
欧尚俄罗斯网上超市:Auchan俄罗斯
2018/05/03 全球购物
EJB包括(SessionBean,EntityBean)说出他们的生命周期,及如何管理事务的
2015/07/24 面试题
学习雷锋精神倡议书
2015/04/27 职场文书