给定两个结构,其中任何一个字段的某些字段可能为null,那么合并它们的最优雅方式是什么? (如果两个都有一个非空的字段,那么取一边?)
我不确定如何在不比较每个字段的情况下执行此操作。
答案 0 :(得分:1)
您还需要问自己以下问题:
在大多数情况下,第一个问题确实不是问题因为通常结果会是nil
。在大多数情况下,第二个问题确实不是问题,因为通常你会定义一些优先级(即第一个参数胜过第二个参数)。
第三个有点棘手。您可以定义采取非零的任何一个。
嵌套也有点棘手。您可能希望"深度合并"一些结构或只是表面上合并一些结构。
无论如何,你可以用reflect
做到这一点,但它会变得棘手(除非有人已经做过)。通过大约5分钟的黑客攻击你可以得到这个:
func f(a,b interface{}) {
ra := reflect.ValueOf(a).Elem()
rb := reflect.ValueOf(b).Elem()
numFields := ra.NumField()
for i := 0; i < numFields; i++ {
field_a := ra.Field(i)
field_b := rb.Field(i)
switch field_a.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
if field_a.IsNil() {
field_a.Set(field_b)
}
}
}
}
但这是完整的FAR,并且它只适用于导出的字段,因为访问未导出的字段对于reflect
来说并不方便,并且需要更多的怪癖来完成它。它也没有递归,但如果你检测到嵌套结构等,你当然可以递归。
但是,如果你只为你的结构编写一个手动合并函数,它可能会更好。
答案 1 :(得分:1)
如果你不太在乎成本。我的解决方案效率很低。使用带有omitempty
标记的json marshal和unmarshal。希望它可以帮助你。
package main
import (
"fmt"
"encoding/json"
)
type myStruct struct{
Id int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Sex bool `json:"sex,omitempty"`
Age int `json:"age,omitempty"`
Addr string `json:"addr,omitempty"`
}
func MergeStruct(to interface{},from interface{}) error{
byte1,err := json.Marshal(to)
if err != nil {
return err
}
byte2,err := json.Marshal(from)
if err != nil {
return err
}
map1 := make(map[string]interface{})
err = json.Unmarshal(byte1,&map1)
if err != nil {
return err
}
map2 := make(map[string]interface{})
err = json.Unmarshal(byte2,&map2)
if err != nil {
return err
}
for k,v := range map2{
map1[k] = v
}
byteDest,err := json.Marshal(map1)
if err != nil {
return err
}
err = json.Unmarshal(byteDest,to)
return err
}
func main() {
st1 := myStruct{
Id:1,
Name:"saky1",
Addr:"addr1",
}
st2 := myStruct{
Id:2,
Name:"saky2",
Age:20,
}
fmt.Println("befor merge: ",st1)
MergeStruct(&st1,&st2)
fmt.Println("after merge: ",st1)
}
输出:
befor merge: {1 saky1 false 0 addr1}
after merge: {2 saky2 false 20 addr1}