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中实现给gif、png、jpeg图片添加文字水印
Apr 26 Golang
golang中的空slice案例
Apr 27 Golang
Golang 空map和未初始化map的注意事项说明
Apr 29 Golang
golang elasticsearch Client的使用详解
May 05 Golang
浅谈golang 中time.After释放的问题
May 05 Golang
golang 实现时间戳和时间的转化
May 07 Golang
Golang 实现获取当前函数名称和文件行号等操作
May 08 Golang
go语言使用Casbin实现角色的权限控制
Jun 26 Golang
golang fmt格式“占位符”的实例用法详解
Jul 04 Golang
GO语言字符串处理函数之处理Strings包
Apr 14 Golang
Go语言测试库testify使用学习
Jul 23 Golang
在ubuntu下安装go开发环境的全过程
Aug 05 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
如何选购合适的收音机
2021/03/01 无线电
用PHP实现小型站点广告管理
2006/10/09 PHP
PHP 开发环境配置(Zend Studio)
2010/04/28 PHP
查找mysql字段中固定字符串并替换的几个方法
2012/09/23 PHP
PHP微信开发之微信消息自动回复下所遇到的坑
2016/05/09 PHP
PHP简单实现合并2个数字键数组值的方法
2017/05/30 PHP
javascript 随机展示头像实现代码
2011/12/06 Javascript
jquery scroll()区分横向纵向滚动条的方法
2014/04/04 Javascript
js实现DOM走马灯特效的方法
2015/01/21 Javascript
jQuery实现限制textarea文本框输入字符数量的方法
2015/05/28 Javascript
Underscore源码分析
2015/12/30 Javascript
ES6的新特性概览
2016/03/10 Javascript
搞定immutable.js详细说明
2016/05/02 Javascript
javascript简单进制转换实现方法
2016/11/24 Javascript
nodejs个人博客开发第五步 分配数据
2017/04/12 NodeJs
浅谈 Vue v-model指令的实现原理
2017/06/08 Javascript
bootstrap+jQuery 实现下拉菜单中复选框全选和全不选效果
2017/06/12 jQuery
利用node实现一个批量重命名文件的函数
2017/12/21 Javascript
vue.js 实现输入框动态添加功能
2018/06/25 Javascript
JavaScript引用类型之基本包装类型实例分析【Boolean、Number和String】
2018/08/09 Javascript
JavaScript中callee和caller的区别与用法实例分析
2019/06/28 Javascript
python中virtualenvwrapper安装与使用
2018/05/20 Python
pygame游戏之旅 创建游戏窗口界面
2018/11/20 Python
python程序变成软件的实操方法
2019/06/24 Python
linux环境下安装python虚拟环境及注意事项
2020/01/07 Python
在 Python 中接管键盘中断信号的实现方法
2020/02/04 Python
Django ForeignKey与数据库的FOREIGN KEY约束详解
2020/05/20 Python
用Python开发app后端有优势吗
2020/06/29 Python
Django实现内容缓存实例方法
2020/06/30 Python
Python  word实现读取及导出代码解析
2020/07/09 Python
CSS3的常见transformation图形变化用法小结
2016/05/13 HTML / CSS
美国家居装饰店:Pier 1
2019/09/04 全球购物
Timberland俄罗斯官方网上商店:全球领先的户外品牌
2020/03/15 全球购物
SQL里面IN比较快还是EXISTS比较快
2012/07/19 面试题
2014植树节活动总结
2014/03/11 职场文书
2015年文员个人工作总结
2015/04/09 职场文书