gitub上星最高的是github.com/jinzhu/copier但是也存在问题,嵌套结构体无法处理copy问题。直接上代码:
package main
import (
"fmt"
"github.com/jinzhu/copier"
)
type BaseModel struct {
Id uint `copier:"must"`
UserId int `copier:"must" json:"userId"`
OemCode string `json:"oemCode" copier:"must"`
}
type User struct {
BaseModel
Name string
Role string
Age int32 `json:"age"`
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, BaseModel: BaseModel{UserId: 1000, OemCode: "nss", Id: 0}}
user2 = User{Name: "Jinzhu1", Age: 20, BaseModel: BaseModel{OemCode: "123213", UserId: 1200, Id: 20}}
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(&user2, &user.BaseModel)//此处无法copy BaseModel中的值
copier.Copy(&user2, &user)//此处无法copy BaseModel中的值
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}
}
通过反射copy两个结构体的值但是也无法直接实现copy。需要提前赋值操作,代码如下:
package utils
import (
"gitlab.starpay.jp/boss/merchant/global"
"reflect"
)
// CopyFields 用b的所有字段覆盖a的
// 如果fields不为空, 表示用b的特定字段覆盖a的
// a应该为结构体指针
func CopyFields(a interface{}, b interface{}, fields ...string) (err error) {
at := reflect.TypeOf(a)
av := reflect.ValueOf(a)
bt := reflect.TypeOf(b)
bv := reflect.ValueOf(b)
// 简单判断下
if at.Kind() != reflect.Ptr {
global.Logger.Error("a must be a struct pointer", "")
return
}
av = reflect.ValueOf(av.Interface())
// 要复制哪些字段
_fields := make([]string, 0)
if len(fields) > 0 {
_fields = fields
} else {
for i := 0; i < bv.NumField(); i++ {
//if bt.Field(i).Name == "Id" {
// continue
//}
_fields = append(_fields, bt.Field(i).Name)
}
}
if len(_fields) == 0 {
global.Logger.Error("no fields to copy", "")
return
}
// 复制
for i := 0; i < len(_fields); i++ {
name := _fields[i]
f := av.Elem().FieldByName(name)
bValue := bv.FieldByName(name)
// a中有同名的字段并且类型一致才复制
if f.IsValid() && f.Kind() == bValue.Kind() {
f.Set(bValue)
} else {
global.Logger.Errorf("no such field or different kind, fieldName: %s\n", name, "")
}
}
return
}
做法就是提前赋值,举例如下
user.Id=user2.Id
utils.CopyFields(&user2, user)
3、目前没有遇到好的方式(小伙伴遇到评论回复)