Выборочное копирование go структурных полей - PullRequest
0 голосов
/ 12 сентября 2018

Я хотел, чтобы выборочно копировал поля 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 голосов
/ 12 сентября 2018

Код будет паниковать, если аргументы не являются указателями на структуры.Есть проверка на указатель, но не на указатель на структуру.Добавьте этот код:

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))
}

Запустить его на детской площадке

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...