Home  >  Article  >  Backend Development  >  What is the correct way to conditionally assign multiple properties to a struct

What is the correct way to conditionally assign multiple properties to a struct

WBOY
WBOYforward
2024-02-06 08:05:11624browse

What is the correct way to conditionally assign multiple properties to a struct

Question content

I am developing a parser function for be's graphql query that I wrote in go. In the parser, I have user data that I want to update, using an input value that contains multiple possible update properties.

In javascript this can be done quickly via destructuring (pseudo):

const mergedobj = {...oldprops, ...newprops}

Currently, my parser function looks like this (using gqlgen as the graphql go parser):

func (r *mutationResolver) ModifyUser(ctx context.Context, input *model.ModifyUserInput) (*model.User, error) {
    id := input.ID
    us, ok := r.Resolver.UserStore[id]
    if !ok {
        return nil, fmt.Errorf("not found")
    }

    if input.FirstName != nil {
        us.FirstName = *input.FirstName
    }

    if input.LastName != nil {
        us.LastName = *input.LastName
    }

    if input.ProfileImage != nil {
        us.ProfileImage = input.ProfileImage
    }

    if input.Password != nil {
        us.Password = *input.Password
    }

    if input.Email != nil {
        us.Email = *input.Email
    }

    if input.InTomorrow != nil {
        us.InTomorrow = input.InTomorrow
    }

    if input.DefaultDaysIn != nil {
        us.DefaultDaysIn = input.DefaultDaysIn
    }

    r.Resolver.UserStore[id] = us

    return &us, nil
}

This feels very simple. Does it make sense to iterate over the struct keys in this case? Or is there another pattern I'm missing?


Correct answer


Use functions to reduce boilerplate:

func mergef[t any](a, b *t) {
    if b != nil {
        *a = *b
    }
}

...
mergef(&us.firstname, input.firstname)
mergef(&us.lastname, input.lastname)
...

Use the reflection package to reduce more boilerplate:

// merge sets fields in struct pointed to by d to 
// dereferenced fields in struct pointed to by s. 
//
// argument s must point to a struct with pointer type
// fields.   
// argument d must point to a struct with fields that 
// correspond to the fields in s: there must be a field
// in d with the same name as a field in s; the type of
// the field in s must be a pointer to the type of the field
// in d.   
func merge(d, s any) {
    sv := reflect.valueof(s).elem()
    dv := reflect.valueof(d).elem()
    for i := 0; i < sv.numfield(); i++ {
        sf := sv.field(i)
        if sf.isnil() {
            continue
        }
        df := dv.fieldbyname(sv.type().field(i).name)
        df.set(sf.elem())
    }
}

Use a function like this:

merge(us, input)

The above is the detailed content of What is the correct way to conditionally assign multiple properties to a struct. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete