我想要一种选择性将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"`
}
答案 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))
}