从REST API调用更新对象 - struct merge?

Jon*_*nar 6 go

我有一个JSON REST API接受稀疏更新,但我提出的模式似乎异常冗长.我是以错误的方式来做这件事的吗?

(假设这是使用没有内置稀疏更新支持的数据存储.)

func choose(a, b *string) *string {
    if a != nil {
        return a
    }
    return b
}

type Model {
    Id     *string `json:"id"`
    Field1 *string `json:"field1"`
    Field2 *string `json:"field2"`
    Field3 *string `json:"field3"`
    ...
}

func (m1 Model) Update(m2 Model) (m3 Model) {
    m3.Id = choose(m2.Id, m1.Id)
    m3.Field1 = choose(m2.Field1, m1.Field1)
    m3.Field2 = choose(m2.Field2, m1.Field2)
    m3.Field3 = choose(m2.Field3, m1.Field3)
    ...
    return
}

func UpdateController(input Model) error {
    previous, _ := store.Get(*input.Id)
    updated := previous.Update(input)
    return store.Put(updated)
}
Run Code Online (Sandbox Code Playgroud)

理想情况下,我可以这样写UpdateController:

func UpdateController(input Model) {
    previous, _ := store.Get(*input.Id)
    updated, _ := structs.Update(previous, input)
    return store.Put(updated)
}
Run Code Online (Sandbox Code Playgroud)

(为清楚起见,错误处理已被省略.)

dav*_*ave 6

好吧,如果您愿意使用反射,问题就变得非常简单了:

http://play.golang.org/p/dc-OnO1cZ4

func (m1 Model) Update(m2 Model) (m3 Model) {
    old := reflect.ValueOf(m1)
    new := reflect.ValueOf(m2)
    final := reflect.ValueOf(&m3).Elem()
    for i := 0; i < old.NumField(); i++ {
        if !new.Field(i).IsNil()  {
           final.Field(i).Set(new.Field(i))
        } else {
           final.Field(i).Set(old.Field(i))
        }      
    }
    return
}
Run Code Online (Sandbox Code Playgroud)

我们这样做的原因reflect.ValueOf(&m3).Elem()是v3需要设置,参见http://blog.golang.org/laws-of-reflection

但基本上,通过使用反射,我们可以循环遍历struct字段,查看更新的字段是否为nil,如果是,则使用旧值.