Skip to content

copier

Dépôt open source : jinzhu/copier: Copier for golang, copy value from struct to struct and more (github.com)

Adresse de la documentation : jinzhu/copier: Copier for golang, copy value from struct to struct and more (github.com)

copier est une bibliothèque pour la copie de types en Go, principalement utilisée pour la conversion entre structures. L'auteur est le même que gorm, elle possède les caractéristiques suivantes :

  • Copie profonde
  • Copie les champs de même nom
  • Copie les slices
  • Copie les maps
  • Copie les méthodes

Comme la copie de copier repose sur la réflexion, il y a une certaine perte de performance. Généralement, ce type de bibliothèque de copie se divise en deux catégories : une basée sur la réflexion, comme copier, et l'autre basée sur la génération de code, qui génère du code de conversion de types. Cette méthode n'entraîne pas de perte de performance. Une bibliothèque similaire est jmattheis/goverter.

Installation

sh
 go get github.com/jinzhu/copier

Utilisation

Cette bibliothèque est très simple à utiliser mais très pratique. Elle expose uniquement deux fonctions. L'une est copier.Copy.

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

L'autre est copier.CopyWithOption, qui permet de personnaliser certains comportements de copie. Par défaut, elle n'effectue pas de copie profonde.

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

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

Voici un exemple de conversion entre structures de types différents. Les structures User et Student sont deux types complètement différents, sans aucune relation.

go
type User struct {
  Id   string
  Name string
  // Lorsque utilisé comme structure cible, ignore ce champ
  Address string `copier:"-"`
}

type Student struct {
  // Spécifie le nom du champ
  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)
}

Sortie

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

Voyons maintenant la copie 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)
}

Sortie

[{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:}]

Copie de map

go
type User struct {
  Id   string
  Name string
  // Lorsque utilisé comme structure cible, ignore ce champ
  Address string `copier:"-"`
}

type Student struct {
  // Spécifie le nom du champ
  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)
}

Sortie

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:}]

Personnalisation

Il est également possible de personnaliser les méthodes de conversion en passant simplement copier.TypeConverter

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

Comme ci-dessous

go
type User struct {
  Id   string
  Name string
  // Lorsque utilisé comme structure cible, ignore ce champ
  Address string `copier:"-"`
}

type Student struct {
  // Spécifie le nom du champ
  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("error type")
          }
          return User{
            Id: s.StudentId,
          }, nil
        },
      },
    },
    FieldNameMapping: nil,
  }); err != nil {
    panic(err)
  }
  fmt.Printf("%+v\n", src)
  fmt.Printf("%+v\n", dest)
}

Sortie

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 by www.golangdev.cn edit