Go语言 有条件地将多个属性分配给结构的正确方法是什么

eagi6jfj  于 2023-01-28  发布在  Go
关注(0)|答案(1)|浏览(104)

我正在为我在Go语言中编写的BE的GraphQL查询编写一个解析器函数,在这个解析器中,我有一些用户数据需要更新,使用的输入值包含了几个可能的更新属性。
在JavaScript中,这可以通过解构(伪)快速完成:
const mergedObj = {...oldProps, ...newProps}
现在,我的解析器函数如下所示(使用gqlgen作为GraphQL Go解析器):

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
}

这让人感觉很老套。在这种情况下遍历结构键有意义吗?或者我遗漏了另一个模式?

gtlvzcf8

gtlvzcf81#

使用函数来减少样板文件:

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

...
mergef(&us.FirstName, input.FirstName)
mergef(&us.LastName, input.LastName)
...

使用reflect包减少更多样板文件:

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

按如下方式使用函数:

merge(us, input)

相关问题