[golang] Go에서 json다루기

강다·2023년 7월 5일
0

코드를 짜던 중 json ↔ []string 변환 사이에서 Marshal, Unmarshal 함수 호출을 했는데, 쓰면서도 계속 두 가지가 헷갈려서 정리를 하게 되었다. 그리고, map[string], interface에 대해서도 한 번 더 짚고 넘어 가려고 한다.

표준 패키지인 encoding/json을 사용하면 된다. 참고로 미리 언급하자면, Marshal을 통해 맵을 JSON문서로 변환 가능하다.



map[string] interface

일반적으로 Go에서 map[string] interface{}를 쓰는 이유는 JSON데이터를 다루기 위함이다. 즉, 문자열 키와 임의의 인터페이스 값을 매핑하는 map으로, 동적으로 key-value 쌍을 저장 가능하다.

Go에서 특정 데이터를 Dictionary로 보관하기 위해선, Key-Value가 어떤 자료형인지 명시해주어야 하므로!!

여러 개의 map[string] interface{}를 가질려면 []map]string]interface{}를 사용하면 된다.

빈 맵 생성을 위해 make함수를 사용할 수도 있다. (맵으로 초기화)

m := make(map[string]interface{})
m["name"] = "Dusdj"
m["age"] = 23
m["Active"] = true 



1. Marshal : golang obejct (string, struct) → []byte, string로 변환
2. Unmarshal : []byte, string → golang object



Marshal

(JSON 포맷으로 인코딩)

func Marshal(v interface{}) ([]byte, error)
  • JSON으로 인코딩된 바이트배열과 에러 객체를 리턴
  • JSON의 key는 문자열이어야 한다!
    • Go 구조체의 경우 자동으로 필드명을 문자열로 사용하지만, map인 경우 map[string]T 처럼 Key가 string인 map만 지원한다.

ex)

package main

import (
	"encoding/json"
	"fmt"
)

type Member struct {
  Name string
	Age int
	Active bool
)

func main() {
	mem := Member{"Dusdj", 23, true}

	//JSON 인코딩
	jsonBytes, err := json.Marshal(mem)
	if err != nil {
		panic(err)
	}

	//JSON 바이트를 문자열로 변경
	jsonString := string(jsonBytes)
	fmt.Println(jsonString)
}



Unmarshal

디코딩

func Unmarshal(data []byte, v interface{}) error 
  • 리턴 값은 에러객체이고, 에러가 없을 경우, 두 번째 파라미터에 원래 데이터가 복원된다.
  • 만약 매칭되는 필드가 구조체에 없다면, 그 값은 무시
  • 출력 구조체나 map을 미리 정의하지 않고 디코딩도 가능하다.
func main() {
	jsonBytes, _ := json.Marshal(Member{"Dusdj", 23, true})

	//JSON 디코딩
	var mem Member
	err := json.Unmarshal(jsonBytes, &mem)
	if err != nil {
		panic(err)
	}

	fmt.Println(mem.Name, mem.Age, mem.Active)
}



++ NewDecoder

NewDecoder랑 Marshalling이랑 헷갈릴 수도 있을 것 같다.

NewDecoder

  • JSON 문자열을 Go Value로 바꾸는 것
  • json.NewDecoder함수로 디코더를 만들게 된 후 json.Decode를 통해 JSON 문자열을 Go Value로 변경
  • 인코딩은 NewEncoder함수로 인코더를 만들고, 이후 json.Encode를 통해 인코딩(다시 JSON문자열로)
  • 패키지를 만드는 함수 json.NewDecoder에 들어가는 인자는 io.Writer 타입을 받게 됨

Marshal

  • JSON 직접 변환이 아니라, 바이트 슬라이스로 변환
  • 보통 Post 요청이 들어오면, ioutil.ReadAll(r.Body)를 통해 바이트 슬라이스로 변경 한 뒤에 사용
  • NewDecoder보다 처리가 편리하고 직관적이어서 많이 사용함
var v map[string]interface{}
data := ioutil.ReadAll(r.Body)
json.Unmarshal(data, &v)  //두번째 인자 : 변수(포인터 값) 

0개의 댓글