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语言中切片与内存复制 memcpy 的实现操作
Apr 27 Golang
golang 实现对Map进行键值自定义排序
Apr 28 Golang
golang 接口嵌套实现复用的操作
Apr 29 Golang
浅谈Go语言多态的实现与interface使用
Jun 16 Golang
Golang并发操作中常见的读写锁详析
Aug 30 Golang
Go语言基础函数基本用法及示例详解
Nov 17 Golang
Golang数据类型和相互转换
Apr 12 Golang
golang使用map实现去除重复数组
Apr 14 Golang
golang语言指针操作
Apr 14 Golang
Golang 链表的学习和使用
Apr 19 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
SMARTY学习手记
2007/01/04 PHP
php调用淘宝开放API实现根据卖家昵称获取卖家店铺ID的方法
2015/07/29 PHP
标准版Eclipse搭建PHP环境的详细步骤
2015/11/18 PHP
php post换行的方法
2020/02/03 PHP
JS小框架 fly javascript framework
2009/11/26 Javascript
学习javascript,实现插入排序实现代码
2011/07/31 Javascript
当json键为数字时的取值方法解析
2013/11/15 Javascript
JavaScript实现在数组中查找不同顺序排列的字符串
2014/09/26 Javascript
浅谈JavaScript Date日期和时间对象
2014/12/29 Javascript
JavaScript实现鼠标点击后层展开效果的方法
2015/05/13 Javascript
javascript检查浏览器是否已经启用XX功能
2015/07/10 Javascript
JS实现响应鼠标点击动画渐变弹出层效果代码
2016/03/25 Javascript
js数组与字符串常用方法总结
2017/01/13 Javascript
Javascript 两种刷新方法以及区别和适用范围
2017/01/17 Javascript
Vue.js基础指令实例讲解(各种数据绑定、表单渲染大总结)
2017/07/03 Javascript
jQuery实现的鼠标滚轮控制图片缩放功能实例
2017/10/14 jQuery
微信小程序引入Vant组件库过程解析
2019/08/06 Javascript
如何利用Python模拟GitHub登录详解
2019/07/15 Python
python 公共方法汇总解析
2019/09/16 Python
简单的Python人脸识别系统
2020/07/14 Python
学习Python爬虫的几点建议
2020/08/05 Python
通过实例解析python and和or使用方法
2020/11/14 Python
Pycharm安装python库的方法
2020/11/24 Python
使用bandit对目标python代码进行安全函数扫描的案例分析
2021/01/27 Python
CSS中越界问题的经典解决方案【推荐】
2016/04/19 HTML / CSS
英国独特的时尚和生活方式品牌:JOY
2018/03/17 全球购物
REN Clean Skincare官网:英国本土有机护肤品牌
2019/02/23 全球购物
《这儿真好》教学反思
2014/02/22 职场文书
初三学习决心书
2014/03/11 职场文书
《春晓》教学反思
2014/04/20 职场文书
法人代表身份证明书及授权委托书
2014/09/16 职场文书
社会主义核心价值观主题教育活动总结
2015/05/07 职场文书
业务员年终工作总结2015
2015/05/28 职场文书
运动会加油稿50字
2015/07/21 职场文书
2016北大自主招生自荐信模板
2016/01/28 职场文书
goland设置颜色和字体的操作
2021/05/05 Golang