Skip to content

copier

Repositorio de código abierto: jinzhu/copier: Copier for golang, copy value from struct to struct and more (github.com)

Dirección de documentación: jinzhu/copier: Copier for golang, copy value from struct to struct and more (github.com)

copier es una biblioteca para realizar copias de tipos en Go, principalmente utilizada para conversiones entre estructuras. El autor es el mismo que gorm, tiene las siguientes características:

  • Copia profunda
  • Copia campos con el mismo nombre
  • Copia slices
  • Copia maps
  • Copia métodos

Dado que la copia de copier depende de la reflexión, habrá cierta pérdida de rendimiento. Generalmente, este tipo de bibliotecas de copia de tipos se dividen en dos categorías, una basada en reflexión, como copier, y otra basada en generación de código, que genera código de conversión de tipos, este método no causa pérdida de rendimiento, bibliotecas similares son jmattheis/goverter.

Instalación

sh
go get github.com/jinzhu/copier

Uso

Esta biblioteca es muy simple de usar, pero muy práctica. Solo expone dos funciones, una es copier.Copy.

go
func Copy(toValue interface{}, fromValue interface{}) (err error)

La otra es copier.CopyWithOption, la segunda permite algunas configuraciones personalizadas para el comportamiento de copia, por defecto no se realiza una copia profunda.

go
type Option struct {
  IgnoreEmpty   bool
  CaseSensitive bool
  DeepCopy      bool
  FieldNameMapping []FieldNameMapping
}

func CopyWithOption(toValue interface{}, fromValue interface{}, opt Option) (err error)

A continuación se muestra un ejemplo de conversión entre estructuras de diferentes tipos, donde User y Student son dos tipos completamente diferentes sin ninguna relación.

go
type User struct {
  Id   string
  Name string
  // Ignorar este campo cuando es la estructura de destino
  Address string `copier:"-"`
}

type Student struct {
  // Especificar nombre de campo
  StudentId   string `copier:"Id"`
  StudentName string `copier:"Name"`
  Address     string
  School      string
  Class       string
}

func main() {
  student := Student{
    StudentId:   "123",
    StudentName: "jack",
    Address:     "usa",
    School:      "MIT",
    Class:       "AI",
  }
  user := User{}
  if err := copier.Copy(&user, &student); err != nil {
    panic(err)
  }
  fmt.Printf("%+v\n", student)
  fmt.Printf("%+v\n", user)
}

Salida

{StudentId:123 StudentName:jack Address:usa School:MIT Class:AI}
{Id:123 Name:jack Address:}

A continuación se muestra la copia de slices

go
func main() {
  student := []Student{
    {
      StudentId:   "123",
      StudentName: "jack",
      Address:     "usa",
      School:      "MIT",
      Class:       "AI",
    },
    {
      StudentId:   "123",
      StudentName: "jack",
      Address:     "usa",
      School:      "MIT",
      Class:       "AI",
    },
  }

  var user []User
  if err := copier.Copy(&user, &student); err != nil {
    panic(err)
  }
  fmt.Printf("%+v\n", student)
  fmt.Printf("%+v\n", user)
}

Salida

[{StudentId:123 StudentName:jack Address:usa School:MIT Class:AI} {StudentId:123 StudentName:jack Address:usa School:MIT Class:AI}]
[{Id:123 Name:jack Address:} {Id:123 Name:jack Address:}]

Copiar map

go
type User struct {
  Id   string
  Name string
  // Ignorar este campo cuando es la estructura de destino
  Address string `copier:"-"`
}

type Student struct {
  // Especificar nombre de campo
  StudentId   string `copier:"Id"`
  StudentName string `copier:"Name"`
  Address     string
  School      string
  Class       string
}

func main() {
  student := Student{
    StudentId:   "123",
    StudentName: "jack",
    Address:     "usa",
    School:      "MIT",
    Class:       "AI",
  }

  src := make(map[string]Student)
  src["a"] = student
  src["b"] = student

  dest := make(map[string]User)

  if err := copier.Copy(&dest, &src); err != nil {
    panic(err)
  }
  fmt.Printf("%+v\n", src)
  fmt.Printf("%+v\n", dest)
}

Salida

map[a:{StudentId:123 StudentName:jack Address:usa School:MIT Class:AI} b:{StudentId:123 StudentName:jack Address:usa School:MIT Class:AI}]
map[a:{Id:123 Name:jack Address:} b:{Id:123 Name:jack Address:}]

Personalización

También se pueden personalizar los métodos de conversión, solo es necesario pasar copier.TypeConverter

go
type TypeConverter struct {
  SrcType interface{}
  DstType interface{}
  Fn      func(src interface{}) (dst interface{}, err error)
}

Como se muestra a continuación

go
type User struct {
  Id   string
  Name string
  // Ignorar este campo cuando es la estructura de destino
  Address string `copier:"-"`
}

type Student struct {
  // Especificar nombre de campo
  StudentId   string `copier:"Id"`
  StudentName string `copier:"Name"`
  Address     string
  School      string
  Class       string
}

func main() {
  student := Student{
    StudentId:   "123",
    StudentName: "jack",
    Address:     "usa",
    School:      "MIT",
    Class:       "AI",
  }

  src := make(map[string]Student)
  src["a"] = student
  src["b"] = student

  dest := make(map[string]User)

  if err := copier.CopyWithOption(&dest, &src, copier.Option{
    IgnoreEmpty:   false,
    CaseSensitive: false,
    DeepCopy:      false,
    Converters: []copier.TypeConverter{
      {
        SrcType: Student{},
        DstType: User{},
        Fn: func(src interface{}) (dst interface{}, err error) {
          s, ok := src.(Student)
          if !ok {
            return User{}, errors.New("tipo de error")
          }
          return User{
            Id: s.StudentId,
          }, nil
        },
      },
    },
    FieldNameMapping: nil,
  }); err != nil {
    panic(err)
  }
  fmt.Printf("%+v\n", src)
  fmt.Printf("%+v\n", dest)
}

Salida

map[a:{StudentId:123 StudentName:jack Address:usa School:MIT Class:AI} b:{StudentId:123 StudentName:jack Address:usa School:MIT Class:AI}]
map[a:{Id:123 Name: Address:} b:{Id:123 Name: Address:}]

Golang editado por www.golangdev.cn