123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- package utils
- import (
- "errors"
- "reflect"
- )
- // check 检查参数
- func check(data interface{}) error {
- if reflect.TypeOf(data).Kind() != reflect.Ptr {
- return errors.New("param must be ptr")
- }
- if reflect.ValueOf(data).IsNil() {
- return errors.New("param can not be nil")
- }
- if reflect.TypeOf(data).Elem().Kind() == reflect.Ptr {
- return errors.New("param must be ptr")
- }
- return nil
- }
- // getFieldArray 获取结构体元素数组
- func getFieldArray(t reflect.Type) (ret []reflect.StructField) {
- for i := 0; i < t.NumField(); i++ {
- field := t.Field(i)
- ret = append(ret, field)
- }
- return ret
- }
- // FieldByTag 根据tag名(tagName)和tag值(tag)从结构体重获取元素
- // 如果tag或tagName为空,则根据元素名称获取元素
- func FieldByTag(value reflect.Value, name string, tag string, tagName string) reflect.Value {
- if tag == "" || tagName == "" {
- return value.FieldByName(name)
- }
- itype := value.Type()
- for i := 0; i < itype.NumField(); i++ {
- v := itype.Field(i)
- if v.Tag.Get(tagName) == tag {
- return value.FieldByIndex(v.Index)
- }
- }
- return reflect.Value{}
- }
- // subStructCopy copy结构体中的子结构体
- func subStructCopy(dst reflect.Value, src reflect.Value, tagName string) {
- fields := getFieldArray(src.Type())
- for _, v := range fields {
- // 获取元素
- srcf := FieldByTag(src, v.Name, v.Tag.Get(tagName), tagName)
- dstf := FieldByTag(dst, v.Name, v.Tag.Get(tagName), tagName)
- // 是否能赋值
- if dstf.CanSet() == false {
- continue
- }
- if dstf.Type() != srcf.Type() {
- // 源和目标类型不一致,基础类型为切片且元素都为结构体,进行切片拷贝
- if v.Type.Kind() == reflect.Slice &&
- dstf.Type().Kind() == reflect.Slice &&
- srcf.Type().Kind() == reflect.Slice &&
- dstf.Type().Elem().Kind() == reflect.Struct &&
- srcf.Type().Elem().Kind() == reflect.Struct {
- array := reflect.MakeSlice(dstf.Type(), 0, 0)
- for i := 0; i < srcf.Len(); i++ {
- item := reflect.New(dstf.Type().Elem())
- subStructCopy(item.Elem(), srcf.Index(i), tagName)
- array = reflect.Append(array, item.Elem())
- }
- dstf.Set(array)
- }
- continue
- }
- // 如果元素是结构体,递归
- if v.Type.Kind() == reflect.Struct {
- subStructCopy(dstf, srcf, tagName)
- continue
- }
- // 拷贝指针指向的数据
- if dstf.Kind() == reflect.Ptr && srcf.IsNil() == false {
- dstf.Set(reflect.New(dstf.Type().Elem()))
- dstf.Elem().Set(srcf.Elem())
- continue
- }
- // 普通数据拷贝
- dstf.Set(srcf)
- }
- }
- // StructCopy 根据tagName(如json)进行结构体拷贝
- // tagName为空,默认按结构体元素名进行拷贝
- func StructCopy(dst interface{}, src interface{}, tagName string) error {
- if err := check(dst); err != nil {
- return err
- }
- if err := check(src); err != nil {
- return err
- }
- srcv := reflect.ValueOf(src).Elem()
- dstv := reflect.ValueOf(dst).Elem()
- subStructCopy(dstv, srcv, tagName)
- return nil
- }
|