Go Unmarshal 일부 불특정 키가 있는 딕셔너리 받기

1 개요[ | ]

Go Unmarshal 불특정 키 대응
  • Go Unmarshal 레이블 딕셔너리 컬럼 받기와 비슷하지만 약간 다른 상황
  • 레이블의 경우는 모든 키를 예측할 수 없는 경우이지만, 여기서는 일부 키는 고정되어 있고 나머지 키는 그렇지 않은 경우를 다룬다.
{"name":"Alice", "age":42, "nickname":"Lisa", "job":"singer"}
{"name":"Bob", "age":3 , "nationality":"Wakanda"}
→ name과 age는 둘다 있지만, nickname, job, nationality는 한쪽에만 있다.

2 방법 1: omitempty[ | ]

  • 나올 수 있는 모든 key를 알고 있을 때, 모두를 구조체의 변수로 달고, 누락될 수 있는 키는 omitempty를 붙인다.
  • 한계점: 완전히 불특정한 경우는 대응할 수 없다. 구조체 내에 변수가 매우 많아질 수 있다.
package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name        string `json:"name"`
	Age         int    `json:"age"`
	Job         string `json:"job,omitempty"`
	Nickname    string `json:"nickname,omitempty"`
	Nationality string `json:"nationality,omitempty"`
}

func unmarshalPerson(bytes []byte, person *Person) {
	if err := json.Unmarshal(bytes, &person); err != nil {
		panic(err)
	}
}

func main() {
	j1 := `{"name":"Alice", "age":42, "nickname":"Lisa", "job":"singer"}`
	j2 := `{"name":"Bob", "age":3 , "nationality":"Wakanda"}`

	person1 := Person{}
	unmarshalPerson([]byte(j1), &person1)
	fmt.Printf("person1: %+v\n", person1)

	person2 := Person{}
	unmarshalPerson([]byte(j2), &person2)
	fmt.Printf("person2: %+v\n", person2)
}

3 방법 2: Unmarshal 2회 수행[ | ]

  • 불특정한 부분만 X map[string]interface{} `json:"-"`와 같이 받고, 그 부분만 한번 더 Unmarshal한다.
  • 단점: nested 구조가 된다.
package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
	Age int `json:"age"`
	X map[string]interface{} `json:"-"`
}

func unmarshalPerson(bytes []byte, person *Person) {
	if err := json.Unmarshal(bytes, &person); err != nil {
		panic(err)
	}
	if err := json.Unmarshal(bytes, &person.X); err != nil {
		panic(err)
	}
	delete(person.X, "name")
	delete(person.X, "age")
}

func main() {
	j1 := `{"name":"Alice", "age":42, "nickname":"Lisa", "job":"singer"}`
	j2 := `{"name":"Bob", "age":3 , "nationality":"Wakanda"}`

	person1 := Person{}
	unmarshalPerson([]byte(j1), &person1)
	fmt.Printf("person1: %+v\n", person1)

	person2 := Person{}
	unmarshalPerson([]byte(j2), &person2)
	fmt.Printf("person2: %+v\n", person2)
}

4 방법 3: interface{}[ | ]

  • 구조체 대신 interface{}를 사용하는 방법
  • 매우 유연하고 간편하지만, 구조가 명확하지 않다. (내부에 어떤 key가 있을지 보장이 없다.)
package main

import (
	"encoding/json"
	"fmt"
)

func unmarshalPerson(bytes []byte, person *interface{}) {
	if err := json.Unmarshal(bytes, &person); err != nil {
		panic(err)
	}
}

func main() {
	j1 := `{"name":"Alice", "age":42, "nickname":"Lisa", "job":"singer"}`
	j2 := `{"name":"Bob", "age":3 , "nationality":"Wakanda"}`

	var person1 interface{}
	unmarshalPerson([]byte(j1), &person1)
	fmt.Printf("person1: %+v\n", person1)

	var person2 interface{}
	unmarshalPerson([]byte(j2), &person2)
	fmt.Printf("person2: %+v\n", person2)
}

5 같이 보기[ | ]

문서 댓글 ({{ doc_comments.length }})
{{ comment.name }} {{ comment.created | snstime }}