应用场景:
copier库允许在go中使用dto,相等于.net automapper
常规用法:更多请移步github
jinzhu/copier: Copier for golang, copy value from struct to struct and more (github.com)
package main
import (
"fmt"
"github.com/jinzhu/copier"
)
type User struct {
Name string
Role string
Age int32
EmployeeCode int64 `copier:"EmployeeNum"` // specify field name
// Explicitly ignored in the destination struct.
Salary int
}
func (user *User) DoubleAge() int32 {
return 2 * user.Age
}
// Tags in the destination Struct provide instructions to copier.Copy to ignore
// or enforce copying and to panic or return an error if a field was not copied.
type Employee struct {
// Tell copier.Copy to panic if this field is not copied.
Name string `copier:"must"`
// Tell copier.Copy to return an error if this field is not copied.
Age int32 `copier:"must,nopanic"`
// Tell copier.Copy to explicitly ignore copying this field.
Salary int `copier:"-"`
DoubleAge int32
EmployeeId int64 `copier:"EmployeeNum"` // specify field name
SuperRole string
}
func (employee *Employee) Role(role string) {
employee.SuperRole = "Super " + role
}
func main() {
var (
user = User{Name: "Jinzhu", Age: 18, Role: "Admin", Salary: 200000}
users = []User{{Name: "Jinzhu", Age: 18, Role: "Admin", Salary: 100000}, {Name: "jinzhu 2", Age: 30, Role: "Dev", Salary: 60000}}
employee = Employee{Salary: 150000}
employees = []Employee{}
)
copier.Copy(&employee, &user)
fmt.Printf("%#v \n", employee)
// Employee{
// Name: "Jinzhu", // Copy from field
// Age: 18, // Copy from field
// Salary:150000, // Copying explicitly ignored
// DoubleAge: 36, // Copy from method
// EmployeeId: 0, // Ignored
// SuperRole: "Super Admin", // Copy to method
// }
// Copy struct to slice
copier.Copy(&employees, &user)
fmt.Printf("%#v \n", employees)
// []Employee{
// {Name: "Jinzhu", Age: 18, Salary:0, DoubleAge: 36, EmployeeId: 0, SuperRole: "Super Admin"}
// }
// Copy slice to slice
employees = []Employee{}
copier.Copy(&employees, &users)
fmt.Printf("%#v \n", employees)
// []Employee{
// {Name: "Jinzhu", Age: 18, Salary:0, DoubleAge: 36, EmployeeId: 0, SuperRole: "Super Admin"},
// {Name: "jinzhu 2", Age: 30, Salary:0, DoubleAge: 60, EmployeeId: 0, SuperRole: "Super Dev"},
// }
// Copy map to map
map1 := map[int]int{3: 6, 4: 8}
map2 := map[int32]int8{}
copier.Copy(&map2, map1)
fmt.Printf("%#v \n", map2)
// map[int32]int8{3:6, 4:8}
}
画风突变情况:
想把用户信息中的用户角色列表转换成[]int32 切片返回给前端,最开始用上面的方法是不行的,没法直接把[]UserRole转换为[]int32,好在打工人不气馁,不妥协,通过不停的试探终于解决了。。。
代码如下
// 用户信息struct
type Users struct {
Account string `json:"account" gorm:"unique;size:50;comment:账号"`
Password string `json:"-" gorm:"comment:密码" copier:"-"`
Slat string `json:"-" gorm:"comment:加密盐" copier:"-"`
Name string `json:"name" gorm:"size:50;comment:姓名"`
Age uint8 `json:"age,omitempty" gorm:"size:4;comment:年龄"`
Gender uint8 `json:"gender,omitempty" gorm:"size:1;comment:性别"`
Phone string `json:"phone,omitempty" gorm:"size:11;comment:电话"`
Email string `json:"email,omitempty" gorm:"size:100;comment:邮箱"`
IsActive bool `json:"isActive,omitempty" gorm:"size:1;comment:是否激活"`
UserRoles []UserRole `json:"roles,omitempty" gorm:"foreignKey:UserID"`
Entity
}
// 需要映射的dto
type UserDto struct {
Account string `json:"account"`
Name string `json:"name"`
Age uint8 `json:"age,omitempty"`
Gender uint8 `json:"gender,omitempty"`
Phone string `json:"phone,omitempty"`
Email string `json:"email,omitempty"`
IsActive bool `json:"isActive"`
IsDelete bool `json:"isDelete"`
CreateBy string `json:"createBy,omitempty"`
CreateTime time.Time `json:"createTime,omitempty"`
UserRoles []int32 `json:"roles,omitempty"`
}
利用copier 的
CopyWithOption 方法自定义映射规则
// 自定义 TypeConverter, Users 转成Dto
var UserToDto = []copier.TypeConverter{
{
// 源类型
SrcType: []domain.UserRole{},
// 映射类型
DstType: []int32{},
// 转换函数
Fn: func(src interface{}) (interface{}, error) {
// 类型断言, 把src转换成domain.UserRole
s, ok := src.([]domain.UserRole)
if !ok {
return nil, errors.New("src type not matching")
}
// 创建RoleID的切片
r := make([]int32, 0)
for _, v := range s {
r = append(r, v.RoleID)
}
return r, nil
},
},
{ // Dto []int32 转 []domain.Users
SrcType: []int32{},
DstType: []domain.UserRole{},
Fn: func(src interface{}) (interface{}, error) {
s, ok := src.([]int32)
if !ok {
return nil, errors.New("src type not matching")
}
r := make([]domain.UserRole, 0)
for _, v := range s {
r = append(r, domain.UserRole{RoleID: v})
}
return r, nil
},
},
}
// 转换的时候,写上以下代码即可,就是这么的简单丝滑
err = copier.CopyWithOption(&udto, user, copier.Option{IgnoreEmpty: true, DeepCopy: true, Converters: contracts.UserToDto})
最终结果:
欢迎大佬指点,讨论。。