Selectively copy go struct fields
Selectively copy go struct fields
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"`
@whitespace OP's code works with the type in question and this type has nested structs.
– ThunderCat
Sep 12 '18 at 5:03
@ThunderCat, I think you misunderstood my concern. I am not talking about first level copy. I think, question is still valid for structs which have structs inside them, where the nested structs have some fields I would want to copy and some fields I don't want to copy.
– whitespace
Sep 12 '18 at 5:08
@whitespace The OP may want to selectively copy within nested structs, but the question does not ask for that feature, nor is that feature needed in all possible uses of the function. Sebastian, do you want to selectively copy within nested structs or do you want to copy nested selects wholesale?
– ThunderCat
Sep 12 '18 at 5:16
@whitespace selectively copying fields within nested structs is beyond the scope of my original question. Maybe someone will have that question down the road however. It could add to the robustness of this code or be part of another question.
– Sebastian
Sep 12 '18 at 13:21
1 Answer
1
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
Thanks for contributing an answer to Stack Overflow!
But avoid …
To learn more, see our tips on writing great answers.
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
This implementation, is also supposed to work when there are structs within structs correct? it fails there. There is a way of doing this using github.com/fatih/structs.
– whitespace
Sep 12 '18 at 4:32