golang
Golang: 같은 필드명을 가진 다른 구조체로 데이터를 옮기기
주먹불끈
2021. 10. 1. 13:29
Photo by Alain Pham on Unsplash
구조체를 정의하고 잘 사용하고 있었는데 특정 필드의 타입이 변경이 된다면 어떻게 데이터를 옮길 수 있을까?
두가지 사례로 실제 코드를 통해 이해해 본다
TL;DR: 기존 구조체 인스턴스를 marshal해서 새로운 구조체 인스턴스로 unmarshaling 해주면, 타입이 달라 충돌이 나는 필드를 제외하고는 가져올 수 있ㄷ.
사례1. string to []string
Playground: https://play.golang.org/p/erJmWKSowPy
Foo 구조체 인스턴스를 Bar 구조체 인스턴스로 옮기려 한다.
여기서는 필드가 두 개 뿐이지만, 필드가 많다면 하나씩 일일이 옮기기 번거롭고 실수를 할 수 있다.
// from
type Foo struct {
Id string `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
}
// to
type Bar struct {
Id string `json:"id"`
Name []string `json:"name"`
Age int `json:"age"`
}
그냥 다짜고짜 foo를 직렬화 - marshalling 해준 다음, bar로 unmarshalling 해주면 된다.
func main() {
foo := Foo{Id: "123", Name: "Joe", Age: 35}
b, err := json.Marshal(foo)
if err != nil {
panic(err)
}
fmt.Println("foo marshalled: ", string(b))
var bar Bar
fmt.Printf("bar initialized: %+v\n", bar)
if err := json.Unmarshal(b, &bar); err != nil {
fmt.Println("incomplete unmarshal: ", err)
}
fmt.Printf("unmarshalled to bar: %+v\n", bar)
bar.Name = make([]string, 1)
bar.Name[0] = foo.Name
fmt.Printf("foo to bar migrated: %+v\n", bar)
}
이때 unmarshaling 중에 아래와 같이 에러가 발생하지만 이걸 무시해주고 진행하는 것이다.
json: cannot unmarshal string into Go struct field Bar.name of type []string
결과는 아래와 같다.
foo marshalled: {"id":"123","name":"Joe","age":35}
bar initialized: {Id: Name:[] Age:0}
incomplete unmarshal: json: cannot unmarshal string into Go struct field Bar.name of type []string
unmarshalled to bar: {Id:123 Name:[] Age:35}
foo to bar migrated: {Id:123 Name:[Joe] Age:35}
사례2. string to int
Playground: https://play.golang.org/p/OneEKm9oV5N
이번에는 string이었던 필드 하나가 int로 바뀐 것이다.
// from
type Foo struct {
Id string `json:"id"`
Age string `json:"age"`
}
// to
type Bar struct {
Id string `json:"id"`
Age int `json:"age"`
}
모두 동일하다. marshal한 다음 unmarshal하면 type이 맞는 필드들은 그대로 값이 전달된다.
에러는 나지만 무시하면 되고, type이 맞지 않는 필드만 수동으로 복사해주는 것이다.
func main() {
foo := Foo{Id: "123", Age: "25"}
b, err := json.Marshal(foo)
if err != nil {
panic(err)
}
fmt.Println("foo marshalled: ", string(b))
var bar Bar
fmt.Printf("bar initialized: %+v\n", bar)
if err := json.Unmarshal(b, &bar); err != nil {
fmt.Println("incomplete unmarshal: ", err)
}
fmt.Printf("unmarshalled to bar: %+v\n", bar)
age, err := strconv.Atoi(foo.Age)
if err != nil {
panic(err)
}
bar.Age = age
fmt.Printf("foo to bar migrated: %+v\n", bar)
}
에러는 나지만 무시하면 되고, type이 맞지 않는 필드만 수동으로 복사해주는 것이다.
foo marshalled: {"id":"123","age":"25"}
bar initialized: {Id: Age:0}
incomplete unmarshal: json: cannot unmarshal string into Go struct field Bar.age of type int
unmarshalled to bar: {Id:123 Age:0}
foo to bar migrated: {Id:123 Age:25}
반응형