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 02 Golang
Golang 正则匹配效率详解
Apr 25 Golang
解决Golang中ResponseWriter的一个坑
Apr 27 Golang
goland 清除所有的默认设置操作
Apr 28 Golang
golang 接口嵌套实现复用的操作
Apr 29 Golang
解决golang结构体tag编译错误的问题
May 02 Golang
golang日志包logger的用法详解
May 05 Golang
go语言中GOPATH GOROOT的作用和设置方式
May 05 Golang
Golang二维数组的使用方式
May 28 Golang
go语言中http超时引发的事故解决
Jun 02 Golang
golang内置函数len的小技巧
Jul 25 Golang
Go 内联优化让程序员爱不释手
Jun 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实现服务器状态监控的方法
2014/12/09 PHP
PHP+Ajax简单get验证操作示例
2019/03/02 PHP
laravel withCount 统计关联数量的方法
2019/10/10 PHP
吐槽一下我所了解的Node.js
2014/10/08 Javascript
jquery实现动态画圆
2014/12/04 Javascript
javascript实现避免页面按钮重复提交
2015/01/08 Javascript
javascript数组排序汇总
2015/07/07 Javascript
JavaScript类型检测之typeof 和 instanceof 的缺陷与优化
2016/01/13 Javascript
js代码实现下拉菜单【推荐】
2016/12/15 Javascript
小程序开发实战:实现九宫格界面的导航的代码实现
2017/01/19 Javascript
从零学习node.js之模块规范(一)
2017/02/21 Javascript
Jquery获取radio选中的值
2017/05/05 jQuery
mongoose设置unique不生效问题的解决及如何移除unique的限制
2017/11/07 Javascript
JavaScript数据结构之单链表和循环链表
2017/11/28 Javascript
ES6/JavaScript使用技巧分享
2017/12/14 Javascript
你应该了解的JavaScript Array.map()五种用途小结
2018/11/14 Javascript
深入理解Node内建模块和对象
2019/03/12 Javascript
Python程序设计入门(3)数组的使用
2014/06/16 Python
Python的净值数据接口调用示例分享
2016/03/15 Python
浅析Python中return和finally共同挖的坑
2017/08/18 Python
Python3 处理JSON的实例详解
2017/10/29 Python
Python代码太长换行的实现
2019/07/05 Python
Python使用tkinter模块实现推箱子游戏
2019/10/08 Python
Python 生成器,迭代,yield关键字,send()传参给yield语句操作示例
2019/10/12 Python
python pptx复制指定页的ppt教程
2020/02/14 Python
Python中bisect的用法及示例详解
2020/07/20 Python
Numpy(Pandas)删除全为零的列的方法
2020/09/11 Python
Python 打印自己设计的字体的实例讲解
2021/01/04 Python
详解Css3新特性应用之过渡与动画
2017/01/10 HTML / CSS
白酒市场开发计划书
2014/01/09 职场文书
学生感冒英文请假条
2014/02/04 职场文书
家具促销活动方案
2014/02/16 职场文书
产品质量承诺范本
2014/03/31 职场文书
投标人廉洁自律承诺书
2014/05/26 职场文书
创先争优活动个人总结
2015/03/04 职场文书
Mysql案例刨析事务隔离级别
2021/09/25 MySQL