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结构体嵌套的切片数组操作
Apr 28 Golang
解决Go gorm踩过的坑
Apr 30 Golang
解决Goland 同一个package中函数互相调用的问题
May 06 Golang
Go 在 MongoDB 中常用查询与修改的操作
May 07 Golang
Go timer如何调度
Jun 09 Golang
详解Go语言Slice作为函数参数的使用
Jul 02 Golang
Golang并发操作中常见的读写锁详析
Aug 30 Golang
Golang bufio详细讲解
Apr 21 Golang
Golang 实现 WebSockets 之创建 WebSockets
Apr 24 Golang
Golang解析JSON对象
Apr 30 Golang
Go语言入门exec的基本使用
May 20 Golang
Go gorilla securecookie库的安装使用详解
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中空字符串介绍0、null、empty和false之间的关系
2012/09/25 PHP
PHP判断一个字符串是否是回文字符串的方法
2015/03/23 PHP
Zend Framework入门知识点小结
2016/03/19 PHP
thinkPHP3.2简单实现文件上传的方法
2016/05/16 PHP
CI框架中数据库操作函数$this-&gt;db-&gt;where()相关用法总结
2016/05/17 PHP
php中的异常和错误浅析
2017/05/03 PHP
jQuery1.6 正式版发布并提供下载
2011/05/05 Javascript
基于jQuery的计算文本框字数的代码
2012/06/06 Javascript
jQuery学习笔记之jQuery.extend(),jQuery.fn.extend()分析
2014/06/09 Javascript
JavaScript实现SHA-1加密算法的方法
2015/03/11 Javascript
NodeJS远程代码执行
2016/08/28 NodeJs
Node.js下自定义错误类型详解
2016/10/17 Javascript
微信小程序五星评分效果实现代码
2017/04/06 Javascript
详解JS数据类型的值拷贝函数(深拷贝)
2017/07/13 Javascript
在vue中使用SockJS实现webSocket通信的过程
2018/08/29 Javascript
详解在Node.js中发起HTTP请求的5种方法
2019/01/10 Javascript
js实现页面多个日期时间倒计时效果
2019/06/20 Javascript
layui table 复选框跳页后再回来保持原来选中的状态示例
2019/10/26 Javascript
JavaScript 实现继承的几种方式
2021/02/19 Javascript
[38:51]2014 DOTA2国际邀请赛中国区预选赛 Orenda VS LGD-CDEC
2014/05/22 DOTA
[56:24]DOTA2上海特级锦标赛主赛事日 - 3 胜者组第二轮#1Liquid VS MVP.Phx第二局
2016/03/04 DOTA
python发布模块的步骤分享
2014/02/21 Python
Python数据结构之栈、队列的实现代码分享
2017/12/04 Python
python pandas库的安装和创建
2019/01/10 Python
Python BeautifulSoup [解决方法] TypeError: list indices must be integers or slices, not str
2019/08/07 Python
一些关于python 装饰器的个人理解
2020/08/31 Python
python安装及变量名介绍详解
2020/12/12 Python
CSS3中的opacity属性使用教程
2015/08/19 HTML / CSS
CSS3 @keyframes简单动画实现
2018/02/24 HTML / CSS
欧洲最大的笔和书写专家:The Pen Shop
2017/03/19 全球购物
在购买印度民族服饰:Soch
2020/09/15 全球购物
股权转让协议书范本
2014/04/12 职场文书
大学新闻系自荐书
2014/05/31 职场文书
学习朴航瑛老师爱岗敬业先进事迹思想汇报
2014/09/17 职场文书
收入证明申请书
2015/06/12 职场文书
浅谈Laravel中使用Slack进行异常通知
2021/05/29 PHP