Skip to content

copier

오픈소스 저장소: jinzhu/copier: Copier for golang, copy value from struct to struct and more (github.com)

문서 주소: jinzhu/copier: Copier for golang, copy value from struct to struct and more (github.com)

copier 는 Go 에서 타입 복사를 위한 라이브러리로 주로 구조체 간 변환에 사용됩니다. 작성자는 gorm 과 동일하며 다음과 같은 특징이 있습니다.

  • 깊은 복사
  • 동일한 이름의 필드 복사
  • 슬라이스 복사
  • map 복사
  • 메서드 복사

copier 의 복사는 리플렉션에 의존하므로 성능상 일정한 손실이 있습니다. 일반적으로 이러한 타입 복사 라이브러리는 두 가지 유형으로 나뉩니다. 하나는 리플렉션 기반인 copier 와 같은 것이고, 다른 하나는 코드 생성 기반으로 타입 변환 코드를 생성하여 성능 손실이 없는 방법이며 유사한 라이브러리로는 jmattheis/goverter 가 있습니다.

설치

sh
 go get github.com/jinzhu/copier

사용

이 라이브러리는 사용법이 매우 간단하지만 매우 실용적입니다. 두 가지 함수만 외부에 노출합니다. 하나는 copier.Copy 입니다.

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

다른 하나는 copier.CopyWithOption 으로 복사 동작에 대해 일부 사용자 정의 구성을 할 수 있으며 기본적으로 깊은 복사를 수행하지 않습니다.

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

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

다음은 다른 타입의 구조체 변환 예제로 UserStudent 구조체는 완전히 다른 타입이며 아무런 연관성이 없습니다.

go
type User struct {
  Id   string
  Name string
  // 대상 구조체일 때 이 필드 무시
  Address string `copier:"-"`
}

type Student struct {
  // 필드명 지정
  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)
}

출력

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

다음은 슬라이스 복사를 봅니다.

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)
}

출력

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

map 복사

go
type User struct {
  Id   string
  Name string
  // 대상 구조체일 때 이 필드 무시
  Address string `copier:"-"`
}

type Student struct {
  // 필드명 지정
  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)
}

출력

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

사용자 정의

변환 방법을 사용자 정의할 수도 있으며 copier.TypeConverter 를 전달하기만 하면 됩니다.

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

다음과 같습니다.

go
type User struct {
  Id   string
  Name string
  // 대상 구조체일 때 이 필드 무시
  Address string `copier:"-"`
}

type Student struct {
  // 필드명 지정
  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)
}

출력

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