选择性复制go struct字段

时间:2018-09-12 03:22:43

标签: go

我想要一种选择性将Go字段从一个结构复制到另一个结构的方法。这使我可以将数据从一个结构更新到另一个结构,而无需更改某些信息。这是我想出的解决方案。这取决于将标记字段设置为“更新”。感谢您提供任何使它变得更健壮或更好的反馈,或者为什么这只是一个不好的主意。

import (
    "errors"
    "fmt"
    "reflect"
)

func UpdateStruct(src, dst interface{}) error {
    if reflect.TypeOf(src) != reflect.TypeOf(dst) {
        return errors.New("structs not of same type")
    }

    if reflect.ValueOf(src).Kind() != reflect.Ptr {
        return errors.New("arguments must be pointers")
    }

    srcVal := reflect.ValueOf(src).Elem()
    srcType := srcVal.Type()

    dstVal := reflect.ValueOf(dst).Elem()

    for i := 0; i < srcVal.NumField(); i++ {
        s := srcType.Field(i)
        if tag := s.Tag.Get("update"); tag == "" {
            continue
        }
        fieldName := srcType.Field(i).Name
        d := dstVal.FieldByName(fieldName)
        if d.IsValid() {
            if d.CanSet() {
                d.Set(srcVal.Field(i))
            } else {
                return fmt.Errorf("cannot set field: %s", fieldName)
            }
        } else {
            return fmt.Errorf("invalid field: %s", fieldName)
        }

    }
    return nil
}

示例结构:

type Tester struct {
    ID      string
    Name    string    `update:"true"`
    Date    time.Time `update:"true"`
    Decimal float64   `update:"true"`
    Number  int       `update:"true"`
    CaseID  uuid.UUID `update:"true"`
}

1 个答案:

答案 0 :(得分:3)

如果参数不是指向结构的指针,则代码将出现恐慌。检查指针,但不检查结构的指针。添加此代码:

srcVal := reflect.ValueOf(src).Elem()
if srcVal.Kind() != reflect.Struct {
    return errors.New("arguments must be pointers to structs")
}

由于该函数从指向结构的指针开始,因此确保可以设置字段。因为字段值是从有效的结构值获得的,所以保证了这些字段是有效的。除名称外,还可以通过索引访问字段。鉴于此,内部循环可以简化为:

for i := 0; i < srcVal.NumField(); i++ {
    s := srcType.Field(i)
    if tag := s.Tag.Get("update"); tag == "" {
        continue
    }
    dstVal.Field(i).Set(srcVal.Field(i))
}

Run it on the playground