【问题标题】:What is the right way to conditionally assign multiple properties to a struct in Golang?在 Golang 中有条件地将多个属性分配给结构的正确方法是什么?
【发布时间】:2023-01-24 14:19:44
【问题描述】:

我正在为一个解析器函数工作图形QL查询我正在编写的 BE戈朗.在解析器中,我有要更新的用户数据,使用包含多个可能更新属性的输入值。

在 javascript 中,这可以通过解构(伪)快速完成:

const mergedObj = {...oldProps, ...newProps}

现在,我的解析器函数看起来像这样(对 GraphQL Go 解析器使用 gqlgen):

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
}

这感觉很样板——在这种情况下遍历结构键是否有意义?还是我缺少另一种模式?

【问题讨论】:

    标签: go graphql conditional-statements gqlgen


    【解决方案1】:

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

    func set[T any](a, b *T) {
        if b != nil {
            *a = *b
        }
    }
    
    ...
    set(&us.FirstName, input.FirstName)
    set(&us.LastName, input.LastName)
    ...
    

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

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

    使用这样的功能:

    rset(us, input)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-31
      • 1970-01-01
      • 1970-01-01
      • 2013-02-02
      • 1970-01-01
      • 2014-04-25
      • 2017-06-06
      • 2021-07-03
      相关资源
      最近更新 更多