많은 Golang 초보자들이 struct를 json으로 마샬링하면서 실수를 하곤한다. 이 문서는 이 문제를 어떻게 해결했는지를 담고 있다.
golang에서 정의된 필드를 사용하지 않는 비어있는 struct를 json으로 마샬링하면, 각 필드가 기본 값을 가진체 마샬링 된다. 때때로 이는 개발자를 혼란스럽게 한다. 아래 코드를 보자.
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string
Age int
}
func main() {
user := User{
Name: "yundream",
Age: 40,
}
encodedData, _ := json.Marshal(user)
fmt.Println(string(encodedData))
}
JSON으로 비 구조적 데이터를 처리하려고 한다면, 값이 없는 필드는 출력하지 않아야 할 것이다. 이름과 나이를 포함하는 설문조사의 경우 설문대상자가 나이를 입력하지 않았다면, 데이터에서 제외해야지 0을 입력해서는 안될 것이다.
해결
빈 구조체(Empty structs)
Age를 입력 받지 않았는데 값으로 0이 입력되는 이유는 Go언어가 마샬링을 할 때 해당 데이터 타입의 기본 값을 입력하기 때문이다. Int 타입의 기본 값은 0이므로 0이 입력된다. 빈 구조체(필드를 정의했으나 사용하지 않는)의 경우 Go 언어는 해당 필드를 기본 값으로 선언하고 마샬링을 한다. 따라서 선언하지 않는 Age 필드에 기본 값인 0이 입력된다.
"omitempty" 태그를 이용해서 문제를 해결 할 수 있다. Go 공식문서는 omitempty를 아래와 같이 설명하고 있다.
The "omitempty" option specifies that the field should be omitted from the encoding if the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string."omitempty" 옵션은 필드에 빈 값이(false, 0, nil 포인터, nil 인터페이스, 빈 배열, 슬라이스, 맵 또는 문자열) 있는 경우 인코딩시 필드를 생략 하도록 지정한다.
User 구조체를 아래와 같이 만들어보자.
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name,omitempty"`
Age int `json:"age,omitempty"`
}
func main() {
user1 := User{
Name: "yundream",
Age: 0,
}
user2 := User{}
encodedData, _ := json.Marshal(user1)
fmt.Println(string(encodedData))
encodedData, _ = json.Marshal(user2)
fmt.Println(string(encodedData))
}
실행해보자.
{"name":"yundream"}
{}
예상대로 잘 작동한다. 중첩된 구조체(nested structs)에서도 잘 작동하는지 테스트해보자. 아래 코드를 실행해보자.
package main
import (
"encoding/json"
"fmt"
)
type Post struct {
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
}
type User struct {
Name string `json:"name,omitempty"`
Age int `json:"age,omitempty"`
Post Post `json:"post,omitempty"`
}
func main() {
user := User{
Name: "yundream",
}
encodedData, _ := json.Marshal(user)
fmt.Println(string(encodedData))
}
실행해보자.
{"name":"yundream","post":{}}
"omitempty" 태그를 사용했음에도 원하는대로 작동하지 않는다. 글을 위로 올려서 omitempty 에 대한 공식설명을 살펴보면 nil pointer에 적용되는 것을 확인 할 수 있다. 아래와 같이 포인터를 사용하도록 코드를 수정했다.
type User struct {
Name string `json:"name,omitempty"`
Age int `json:"age,omitempty"`
Post *Post `json:"post,omitempty"`
}
실행해보자.
{"name":"yundream"}
3레벨 이상의 중첩 구조체
3레벨 이상의 복잡한 구조체는 어떨지 테스트했다.
package main
import (
"encoding/json"
"fmt"
)
type Comment struct {
Description string `json:"description,omitempty"`
Score int `json:"score,omitempty"`
}
type Post struct {
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
Comment *Comment `json:"comment,omitempty"`
}
type User struct {
Name string `json:"name,omitempty"`
Age int `json:"age,omitempty"`
Post *Post `json:"post,omitempty"`
}
func main() {
user := User{
Name: "yundream",
Post: &Post{
Title: "GoLang",
Description: "blah blah....",
},
}
encodedData, _ := json.Marshal(user)
fmt.Println(string(encodedData))
}
Contents
struct를 marshaling 하는 옳은 방법
해결
빈 구조체(Empty structs)
3레벨 이상의 중첩 구조체
Recent Posts
Archive Posts
Tags