doupeizheng3918 2018-09-12 03:22
浏览 74

选择性复制go struct字段

I wanted a way to selectively copy Go fields from one struct to another. This allows me to update data from one struct to another without changing certain information. Here's the solution I came up with. It depends on setting a tag field of "update". Would appreciate any feedback for making this more robust or better or maybe why this is just a bad idea to begin with.

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
}

example struct:

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条回答 默认 最新

  • doupoji3856 2018-09-12 04:53
    关注

    The code will panic if the arguments are not pointers to structs. There'a check for a pointer, but not for a pointer to a struct. Add this code:

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

    Because the function is starting with a pointer to a struct, the fields are guaranteed to be settable. Because the field values are obtained from a valid struct value, the fields are guaranteed to be valid. Fields can be accessed by index in addition to by name. Given this, the inner loop can be simplified to:

    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

    评论

报告相同问题?

悬赏问题

  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法
  • ¥15 可否在不同线程中调用封装数据库操作的类
  • ¥15 微带串馈天线阵列每个阵元宽度计算
  • ¥15 keil的map文件中Image component sizes各项意思
  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据