Golang结构体值的交换

一、添加结构体,多if暴力

最先遇到这个问题是在比编写PUT方法的接口时遇到。

(我公司编写http put方法,是先解析json至StudentInput结构体中,通过if input.Name!=nil来判断是否需要修改原数据的值)

解决方法是增加一个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
}
......
}

这个做法是标准,只是我认为太繁琐想简化一下,参考这篇文章

二、设置tag,利用反射代替多if

最近看了波罗学大佬的一篇文章,突发奇想,可以使用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 内部结构不确定的情况

Golang结构体值的交换的更多相关文章

  1. golang 结构体中的匿名接口

    golang 结构体中的匿名接口 代码示例 golang 中,可以给结构体增加匿名field,可参考 unknwon 大神的书. 匿名字段和内嵌结构体 但,golang同时也可以给结构体定义一个匿名i ...

  2. golang结构体json格式化的时间格式

    golang结构体json格式化的时间格式 在我们开发中,经常会解析time.Time 往往前台传过来的时候,是个string 但是我们希望在结构体转成time.Time type Param str ...

  3. GO开发[五]:golang结构体struct

    Go结构体struct Go语言的结构体(struct)和其他语言的类(class)有同等的地位,但Go语言放弃了包括继承在内的大量面向对象特性,只保留了组合(composition)这个最基础的特性 ...

  4. golang结构体、接口、反射

    struct结构体 struct用来自定义复杂数据结构,可以包含多个字段属性,可以嵌套; go中的struct类型理解为类,可以定义方法,和函数定义有些许区别; struct类型是值类型. struc ...

  5. golang结构体

    声明结构体 定义结构体使用struct关键字.在结构体内部定义它们的成员变量和类型.如果成员变量的类型相同还可以把它们写到同一行. struct里面可以包含多个字段(属性) struct类型可以定义方 ...

  6. Golang结构体struct的使用(结构体嵌套, 匿名结构体等)

    转自: https://studygolang.com/articles/11313 golang中是没有class的,但是有一个结构体struct,有点类似,他没有像java,c++中继承的概念,但 ...

  7. 【转】golang 结构体和方法

    原文:https://www.jianshu.com/p/b6ae3f85c683 ---------------------------------------------------------- ...

  8. golang 结构体嵌入和匿名成员

    考虑一个二维的绘图程序,提供了一个各种图形的库,例如矩形.椭圆形.星形和轮形等几 何形状.这里是其中两个的定义 type Circle struct { X, Y, Radius int } type ...

  9. [Go] golang结构体成员与函数类型

    package main import ( "fmt" ) //定义一个类型 type tsh struct { //定义成员,类型是func() string test func ...

随机推荐

  1. centos系统 通过命名查找需要安装哪个安装包 command not found

    场景: 服务器未安装命令,但是我们需要使用,不知道该安装什么包,以sz命令为例 [root@localhost linshi]# sz tes.sh -bash: /usr/bin/sz: 没有那个文 ...

  2. Vue iview 表单封装验证

    以下内容转自iview社区,仅供自己查看使用 Form表单部分 <div> <Form ref="FormOne" :model="FormOne&qu ...

  3. Python 时间 time

    import time print time.strftime("%Y-%m-%d") import datetime print datetime.datetime.now() ...

  4. bash cheat

    ############################################################################### BASH CHEATSHEET (中文速 ...

  5. 工程日记之HelloSlide(3):如何使用Core Data数据库,以及和sqlite之间的对应关系

    Core Data 和 SQLite 是什么关系 core data是对sqlite的封装,因为sqlite是c语言的api,然而有人也需要obj-c的api,所以有了core data ,另外,co ...

  6. aliyun服务器lamp配置

    1.安装Apache:yum install httpd 2.安装php: yum install php 3.安装mysql客户端:yum install mysql 4.安装mysql服务端:yu ...

  7. js对象属性名和属性值生成新数组时都作为属性值

    const obj = { id:1, name:'zhangsan', age:18 } const arr = []; Object.getOwnPropertyNames(obj).forEac ...

  8. Thread--停止线程

    参考:http://blog.sina.com.cn/s/blog_6ca570ed01016mti.html Thread.interrupt()方法不会中断一个正在运行的线程.它的作用是,在线程受 ...

  9. nginx_tcp_proxy代理酸酸乳

    一.安装低版本的nginx(高版本不支持tcp代理模块:nginx_tcp_proxy_module)Nginx默认只支持http反向代理,要支持tcp反向代理,需在编译时增加tcp代理模块[ngin ...

  10. 用Pandas Dataframe来抓取重构金融股票的各种业务&数据形态

    4. 如果计算各项股票指标时,或者处理业务流程时,上一篇的直观认知数据结构,怎样帮助开发者去好好操作,又同时避免计算错误的坑. 首先从上篇的数据结据,可以看出/设计出多少种业务和股票指标. A. 恒生 ...