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. 解决fixed布局里内容不滚动问题

    //注意给父级加上 (1)横向滚动 left:0; right:0; 然后想要横向滚动的话 overflow-x:scroll; overflow-y:hidden; (2)竖直方向滚动top:0;b ...

  2. java使用mongoTemplate去重排序查询

    import org.springframework.data.mongodb.core.MongoTemplate;import org.springframework.data.mongodb.c ...

  3. STM32速度---网页讲解

    1. ① USART串口,若最大波特率只需115.2k,那用2M的速度就够了,既省电也噪声小. ② I2C接口,若使用400k波特率,若想把余量留大些,可以选用10M的GPIO引脚速度. ③ SPI接 ...

  4. 18 12 2 数据库 sql 的增删改查

    ---恢复内容开始--- 1  开始进入MySQL 的安装  https://www.cnblogs.com/ayyl/p/5978418.html  膜拜大神的博客 2  默认安装的时候     m ...

  5. k8认证机制

    参考下面博文 http://www.mamicode.com/info-detail-2270627.html 需要补充: k8s的的认证机制场景使用 客户端证书认证         采用双向证书进行 ...

  6. hdu 6581 Vacation【思维】

    原题链接: http://acm.hdu.edu.cn/showproblem.php?pid=6581 VacationTime Limit: 10000/5000 MS (Java/Others) ...

  7. 大数据攻城狮之进阶技能-使用Git上传自己的项目至GitHub仓库

    在开始讲解之前我们默认已经存在仓库和安装Git,没有下载的可以去https://git-scm.com/ Git官方网站下载或者是私聊博主. 下面我们说一说Git的使用,比如说如何生成密钥,连接远程仓 ...

  8. Freemarker的一点延生

    1.freemarker一般不是单独使用,他可以和activeMQ互相结合,来完成功能的. 使用它有 几点好处, 首先就是提高程序效率,一般情况我们的页面都是jsp,而jsp实际上是servlet,在 ...

  9. (转)mysql语句

    一.基础 1.说明:创建数据库 CREATE DATABASE database-name 2.说明:删除数据库 drop database dbname 3.说明:备份sql server --- ...

  10. UML-快速的更新分析

    1.目标 本章主要介绍需求和领域分析中的一些变更. 迭代1阶段:结束时,举行为期1-2天的简短的需求讨论会,内容是调查和详细编写更多需求+解决初始阶段反馈问题. 迭代2阶段:结束时,举行为期1-2天的 ...