前言

日常开发中会遇到给 结构体 赋值,场景:struct A,struct B,而A是B的子集,即:

 type A  struct  {
Name string
}
type B struct {
 Name string
 ....
  
}  

将A的值赋值给B

场景: Struct A,struct B,A中某几个字段赋值给B对应字段。

以上场景如一个个字段写赋值太麻烦,这里想写一个方法实现结构体间赋值操作,实现方式自然离不开reflect。

示例

 package main

 import  (
"fmt"
"reflect"
)

func main() {
type A struct {
Name string
Id int
state int
}
type B struct {
Name string
Id int
state int
}
a:=A{Name: "aaa",Id: 11,state: 1}
b:=B{}
//结构
bb:=CopyStruct(a, &b)
fmt.Println(bb)
}

//将结构体source复制给dst,只复制相同名称和相同类型的
//CopyStruct(a,b)  a可以传值,引用,b只能引用,且
func CopyStruct(src ,dst interface{}) interface{} {
st := reflect.TypeOf(src)
sv := reflect.ValueOf(src)
dt := reflect.TypeOf(dst)
dv := reflect.ValueOf(dst)
if st.Kind()==reflect.Ptr {//处理指针
st=st.Elem()
sv=sv.Elem()
}
if dt.Kind()==reflect.Ptr { //处理指针
dt=dt.Elem()
}
if st.Kind()!=reflect.Struct||dt.Kind()!=reflect.Struct {//如果不是struct类型,直接返回dst
return dst
}

dv = reflect.ValueOf(dv.Interface())
// 遍历TypeOf 类型
for i := 0; i < dt.NumField(); i++ { //通过索引来取得它的所有字段,这里通过t.NumField来获取它多拥有的字段数量,同时来决定循环的次数
f := dt.Field(i)               //通过这个i作为它的索引,从0开始来取得它的字段
dVal := dv.Elem().Field(i)
sVal:=sv.FieldByName(f.Name)
//fmt.Println(dVal.CanSet())
//src数据有效,且dst字段能赋值,类型一致
if sVal.IsValid() && dVal.CanSet() && f.Type.Kind()==sVal.Type().Kind() {
dVal.Set(sVal)
}
}
return dst
}