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 가 있습니다.
설치
go get github.com/jinzhu/copier사용
이 라이브러리는 사용법이 매우 간단하지만 매우 실용적입니다. 두 가지 함수만 외부에 노출합니다. 하나는 copier.Copy 입니다.
func Copy(toValue interface{}, fromValue interface{}) (err error)다른 하나는 copier.CopyWithOption 으로 복사 동작에 대해 일부 사용자 정의 구성을 할 수 있으며 기본적으로 깊은 복사를 수행하지 않습니다.
type Option struct {
IgnoreEmpty bool
CaseSensitive bool
DeepCopy bool
FieldNameMapping []FieldNameMapping
}
func CopyWithOption(toValue interface{}, fromValue interface{}, opt Option) (err error)다음은 다른 타입의 구조체 변환 예제로 User 와 Student 구조체는 완전히 다른 타입이며 아무런 연관성이 없습니다.
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:}다음은 슬라이스 복사를 봅니다.
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 복사
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 를 전달하기만 하면 됩니다.
type TypeConverter struct {
SrcType interface{}
DstType interface{}
Fn func(src interface{}) (dst interface{}, err error)
}다음과 같습니다.
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:}]