使用 github.com/jinzhu/copier
进行结构体数据拷贝
1. 介绍
在 Go 语言开发中,我们经常需要在不同的结构体之间复制数据。例如:
- 复制数据库模型到 DTO(数据传输对象)
- 复制请求参数到业务层对象
- 复制多个字段的结构体到另一个结构体
- gRPC .proto 文件生成的结构体自带内置字段导致用户自定义字段赋值繁琐
如果手动复制,每个字段都需要显式赋值,代码冗长且容易出错。因此,我们可以使用 jinzhu/copier
这个第三方库来简化这个过程。
地址:GitHub - jinzhu/copier: Copier for golang, copy value from struct to struct and more
2. copier
解决的问题
- 减少冗余代码:无需手动赋值每个字段。
- 支持结构体到结构体的拷贝:即使目标结构体的字段是源结构体的子集或超集。
- 支持指针和非指针类型:能够处理
struct
和*struct
之间的转换。 - 支持字段名相同的映射:只会拷贝名称匹配的字段。
- **支持 **
** 到 **
:可以将map[string]interface{}
复制到结构体。
3. 安装 copier
go get github.com/jinzhu/copier
4. 使用示例
4.1 结构体到结构体的拷贝
PS:使用过 gRPC 中 .proto 文件定义的结构体默认自带三个内置字段,剩余用户自定义字段赋值通过这种方式简直不要太爽
package main
import (
"fmt"
"github.com/jinzhu/copier"
)
type User struct {
ID int
Name string
Age int
}
type UserDTO struct {
Name string
Age int
}
func main() {
user := User{ID: 1, Name: "Alice", Age: 25}
var userDTO UserDTO
// 复制数据
copier.Copy(&userDTO, &user)
fmt.Println(userDTO) // 输出: {Alice 25}
}
4.2 结构体切片拷贝
func main() {
users := []User{
{ID: 1, Name: "Alice", Age: 25},
{ID: 2, Name: "Bob", Age: 30},
}
var userDTOs []UserDTO
copier.Copy(&userDTOs, &users)
fmt.Println(userDTOs) // 输出: [{Alice 25} {Bob 30}]
}
4.3 指针结构体拷贝
func main() {
user := &User{ID: 1, Name: "Alice", Age: 25}
var userDTO UserDTO
copier.Copy(&userDTO, user)
fmt.Println(userDTO) // 输出: {Alice 25}
}
4.4 处理不同字段类型
type UserExtended struct {
ID int
Name string
Age int
IsActive bool
JoinDate string
}
type UserSummary struct {
FullName string `copier:"Name"`
Active bool `copier:"IsActive"`
}
func main() {
user := UserExtended{ID: 1, Name: "Alice", Age: 25, IsActive: true, JoinDate: "2023-01-01"}
var summary UserSummary
copier.Copy(&summary, &user)
fmt.Println(summary) // 输出: {Alice true}
}
4.5 map
到 struct
的拷贝
func main() {
data := map[string]interface{}{
"Name": "Charlie",
"Age": 28,
}
var user UserDTO
copier.Copy(&user, &data)
fmt.Println(user) // 输出: {Charlie 28}
}
5. 结论
github.com/jinzhu/copier
提供了一种简洁高效的方法来在结构体、切片和 map
之间拷贝数据,减少手动字段映射的工作量,提升代码可读性。