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
go get github.com/jinzhu/copierUso
Esta biblioteca es muy simple de usar, pero muy práctica. Solo expone dos funciones, una es copier.Copy.
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.
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.
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
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
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
type TypeConverter struct {
SrcType interface{}
DstType interface{}
Fn func(src interface{}) (dst interface{}, err error)
}Como se muestra a continuación
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:}]