Go使用copier库

前言

最近在重构公司项目的model层,发现在数据库model向返回ack model之间的结构体转换时,因为model字段多,则存在大量的直接赋值,不美观也不优雅,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func (person *Person) MapTo() model.Student {
var student model.Student
now := time.Now()
student.ID=person.ID
student.Name=persobn.Name
student.Age=persobn.Age
student.Phone=persobn.Phone
student.Address=persobn.Address
student.Gender=persobn.Gender
student.ParentPhone=persobn.ParentPhone
student.Mother=persobn.Mother
student.Father=persobn.Father
student.Socre=100
return studnet
}

而使用Go的copier库可以完成不同类型结构体相同字段的赋值,并且还可以完成不同字段的赋值,下面将进行简单的演示

安装

1
go get github.com/jinzhu/copier

使用

字段名相同,类型相同

对于不同类型的结构体,如果字段名相同且字段类型相同,那么copier就会对该字段直接赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
type Person struct {
ID int
Name string
Age int
Address string
}

type Student struct {
ID int
Name string
Age int
Address string
}

func main() {
person := Person{
ID: 1,
Name: "snow",
Age: 22,
Address: "China",
}
var student Student
copier.Copy(&student, &person)
fmt.Println(student)
}
//{1 snow 22 China}

字段名相同,类型不同

对于这种情况copier是不会赋值的,则需要自己手动配置 (所以在model 和 ack间尽量不要设置字段名相同而类型不同)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
type Person struct {
ID int
Name string
Age int
Parent []string
}

type Student struct {
ID int
Name string
Age int
Parent string
}

func main() {
person := Person{
ID: 1,
Name: "snow",
Age: 22,
Parent: []string{"mother", "father"},
}
var student Student
copier.Copy(&student, &person)
student.Parent=strings.Join(person.Parent,",") //这里需要手动配置
}

目标对象中出现不同字段名,但与源对象字段相关

有时候源对象某个字段没有出现在目标对象中,但是目标对象可以使用一个相同字段名的方法,方法接收相同类型的参数,这样在copier Copy时会以源对象的这个字段作为参数调用目标对象的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
type Person struct {
ID int
Name string
Age int
Nation string
}

type Student struct {
ID int
Name string
Age int
Address string
}

func (student *Student) Nation(nat string) { //以源对象字段名相同的目标对象方法
student.Address=nat+"BeiJin"
}

func main() {
person := Person{
ID: 1,
Name: "snow",
Age: 22,
Nation: "China",
}
var student Student
copier.Copy(&student, &person)
fmt.Println(student)
}
//{1 snow 22 ChinaBeiJin}

目标对象中出现不同字段名,但与源对象字段无关

对于这种情况就和字段名相同类型不同的方法一样,需要对这个字段单独处理

不同类型切片的赋值

1
2
3
4
5
6
7
8
9
10
func main() {
persons := []Person{
{ID: 1, Name: "snow",Age: 22},
{ID: 2, Name: "ice",Age: 18},
}
var students []Student
copier.Copy(&students, &persons)
fmt.Println(students)
}
//[{1 snow 22} {2 ice 18}]

结构体复制到切片

根据源对象生成一个和目标切片类型相符合的对象,然后append到目标切片

1
2
3
4
5
6
7
8
9
10
11
func main() {
person := Person{
ID: 1,
Name: "snow",
Age: 22,
}
var students []Student
copier.Copy(&students, &person)
fmt.Println(students)
}
//[{1 snow 22}]

总结

copier库

copier还有很多玩法,本文章值列举了自己在改造时使用过的方法,具体信息可以看官方源码和文档


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!