Golang结构体值的交换
一、最初的做法
最先遇到这个问题是在比编写PUT方法的接口时遇到。
解决方法是增加一个Input struct,该struct字段的变量都为原结构体的指针类型。
优点:可以根据业务逻辑做出改变。
缺点:冗余、易错(每次测试PUT方法时,需要特别小心)。
代码如下:
type Student struct { ID string `json:"id" Name string `json:"name" Age int `json:"age" } type StudentInput struct { ID *string `json:"id" ` Name *string `json:"name"` Age *int `json:"age" ` } func Handle() { var source Student var input StudentInput ...... if input.Name != nil { source.Name = *input.Name } ...... }
二、升级版本
最近看了波罗学大佬的一篇文章,突发奇想,可以使用Go的反射实现交换struct中的值。
类似的作品就想到了开源的mapstruct,参考了一下源码,写了一个劣质Demo。
代码如下:
func Swap(source, input interface{}) error { sourceVal := reflect.ValueOf(source) inputVal := reflect.ValueOf(input) if sourceVal.Kind() != reflect.Ptr { return errors.New("source must be a pointer") } if inputVal.Kind() != reflect.Struct { return errors.New("input must be a struct") } defer func() { if r := recover(); r != nil { log.Println(r) return } }() for i := 0; i < inputVal.NumField(); i++ { for j := 0; j < sourceVal.Elem().NumField(); j++ { // 零值处理 if inputVal.Field(i).IsZero() { continue } // 比较tag if tagEqual(sourceVal.Type().Elem().Field(j), inputVal.Type().Field(i)) { sourceVal.Elem().Field(i).Set(inputVal.Field(j)) break } } } return nil } func tagEqual(s1, s2 reflect.StructField) bool { return s1.Tag.Get("swapstruct") == s2.Tag.Get("swapstruct") }
思路很简单,需要修改的字段在tag中增加swapstruct,运用反射查找相同tag修改值。
优点:简单,不容易出错。
缺点:性能较差。
测试代码如下:
type Student struct { ID string `json:"id" swapstruct:"id"` Name string `json:"name" swapstruct:"name"` Age int `json:"age" swapstruct:"age"` } func main() { id := "inputID" name := "inputName" //age := 0 input := Student{ ID: id, Name: name, //Age: age, } source := Student{ ID: "sourceID", Name: "sourceName", Age: 22, } fmt.Println("source: ", source) fmt.Println("input: ", input) if err := Swap(&source, input); err != nil { log.Println(err) } fmt.Println("after: ", source) }
三、参考
1.mapstructure: https://github.com/mitchellh/mapstructure
2.Go 如何解析 json 内部结构不确定的情况
来源:https://www.cnblogs.com/clod777/p/12022654.html