go处理两个结构体copy问题

  1. 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}
}
  1. 通过反射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、目前没有遇到好的方式(小伙伴遇到评论回复)

你可能感兴趣的:(go读书笔记,go,golang,json,struct)