Go의 JSON을 이해합니다.

5768 단어
이 글은 Go 공식 및https://eager.io/blog/go-and-json/번역과 정리를 했어요.
JSON은 경량급 데이터 교환 형식으로 전후단 데이터 교환으로 자주 사용되며 Go는 encoding/json 패키지에서 JSON에 대한 지원을 제공한다.
서열화
Go struct를 JSON 객체로 시리얼화하고 Go는 Marshal 방법을 제공하며 의미와 같이 시리얼화하고 함수 서명은 다음과 같습니다.
func Marshal(v interface{}) ([]byte, error)

예를 들면 다음과 같은 Go struct가 있습니다.
type Message struct {
 Name string
 Body string
 Time int64
}

Marshal 시리얼을 사용하여 다음을 수행합니다.
m := Message{"Alice", "Hello", 1294706395881547000}
b, err := json.Marshal(m) 
fmt.Println(b) //{"Name":"Alice","Body":"Hello","Time":1294706395881547000}

Go에서 모든 유형이 서열화되는 것은 아닙니다.
  • JSON object 키는 string
  • 만 지원
  • Channel,complex,function 등 type을 서열화할 수 없음
  • 데이터에 순환 인용이 존재하면 서열화할 수 없습니다. 서열화할 때 귀속되기 때문입니다
  • Pointer 서열화 이후 지향하는 값 또는 nil
  • 주의해야 할 것은 struct에서 내보내기를 지원하는 필드만 JSON 패키지 서열화, 즉 알파벳 대문자field입니다.
    역서열화
    역정렬 함수는 Unmarshal이며 함수 서명은 다음과 같습니다.
    func Unmarshal(data []byte, v interface{}) error
    

    역정렬을 수행하려면 먼저 데이터를 정렬할 수 있는 Go struct를 만들어야 합니다.
    var m Message
    err := json.Unmarshal(b, &m)
    

    JSON 대상은 일반적으로 소문자로 표시된다. Marshal 이후에도 JSON 대상의 알파벳은 대문자로 되어 있다. 서열화된 후에 명칭이 어떻게 실현되는지 바꾸려면 답은 struct tags이다.
    Struct Tag
    Struct tag은 Marshal 및 Unmarshal 함수에서 데이터를 시리얼화하고 반시리얼화하는 방법을 결정합니다.
    JSON filed name 지정
    JSON object의 name은 일반적으로 소문자로 작성되므로 struct tag을 통해 다음을 수행할 수 있습니다.
    type MyStruct struct {
     SomeField string `json:"some_field"`
    }
    

    SomeField 서열화하면 somefield.
    필드가 empty일 때의 행동 지정하기omitempty를 사용하면 Marshal 함수를 알려 줍니다. 필드의 값이 대응하는 종류의zero-value라면, 서열화된 JSON object에 이 필드가 포함되지 않습니다.
    type MyStruct struct {
     SomeField string `json:"some_field,omitempty"`
    }
    
    m := MyStruct{}
    b, err := json.Marshal(m) //{}
    
    SomeField == “”라면, 서열화된 대상은 {}이다.
    필드 건너뛰기
    Struct tag "-"은(는) 지정된 filed를 건너뛰는 것을 나타냅니다.
    type MyStruct struct {
     SomeField string `json:"some_field"`
     Passwd string `json:"-"`
    }
    m := MyStruct{}
    b, err := json.Marshal(m) //{"some_feild":""}
    

    즉, 서열화할 때 출력하지 않기 때문에 보호해야 할 필드가 서열화되지 않도록 효과적으로 보호할 수 있다.
    임의의 JSON 데이터 역정렬
    기본 JSON은 다음과 같은 Go 유형만 지원합니다.
  • bool for JSON booleans
  • float64 for JSON numbers
  • string for JSON strings
  • nil for JSON null

  • 서열화하기 전에 JSON 데이터 형식을 모르면 interface{}로 저장합니다.interface {}의 역할은 본보의 다른 문장을 참조한다.
    다음과 같은 데이터 형식이 있습니다.
    b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
    

    만약 우리가 서열화하기 전에 그 데이터 형식을 몰랐다면, 우리는 interface{}를 사용하여 우리의 decode 이후의 데이터를 저장할 수 있다.
    var f interface{}
    err := json.Unmarshal(b, &f)
    

    역서열화 후 f는 다음과 같아야 한다.
    f = map[string]interface{}{
     "Name": "Wednesday",
     "Age":  6,
     "Parents": []interface{}{
     "Gomez",
     "Morticia",
     },
    }
    

    키는string이고value는interface {}에 저장됩니다.f의 데이터를 얻으려면 type assertion을 하고 range를 통해 f의 모든 키를 교체해야 합니다.
    m := f.(map[string]interface{})
    for k, v := range m {
     switch vv := v.(type) {
     case string:
     fmt.Println(k, "is string", vv)
     case float64:
     fmt.Println(k, "is float64", vv)
     case []interface{}:
     fmt.Println(k, "is an array:")
     for i, u := range vv {
     fmt.Println(i, u)
     }
     default:
     fmt.Println(k, "is of a type I don't know how to handle")
     }
    }
    

    슬라이스, 맵,pointer에 대한 반서열화 처리
    우리는 struct를 정의하여 상기 예의 b를 계속 반서열화합니다.
    type FamilyMember struct {
     Name    string
     Age     int
     Parents []string
    }
    
    var m FamilyMember
    err := json.Unmarshal(b, &m)
    

    이 예는 정상적으로 작동할 수 있다는 것을 분명히 알 수 있다. struct에는 슬라이스Parents가 포함되어 있는데 슬라이스는 기본적으로nil이다. 반서열화가 정상적으로 진행될 수 있는 이유는 Unmarshal이 서열화할 때 슬라이스Parents를 초기화했기 때문이다. 같은 이치로 맵과 Pointer에 대해 비슷한 작업을 할 수 있기 때문이다.예를 들어 서열화 만약에 Pointer가 nil이 먼저dereference를 진행하지 않으면 그 지향하는 값을 얻은 다음에 서열화를 하고 반서열화할 때 우선nil pointer를 초기화한다
    Stream JSON
    Go는 marshal과 unmarshal 함수를 제외하고 Decoder와 Encoder가 stream JSON을 처리하고 흔한 Request의 Body, 파일 등을 제공합니다.
    jsonFile, err := os.Open("post.json")
    if err != nil {
     fmt.Println("Error opening json file:", err)
     return
    }
    
    defer jsonFile.Close()
    decoder := json.NewDecoder(jsonFile)
    for {
     var post Post
     err := decoder.Decode(&post)
     if err == io.EOF {
     break
     }
    
     if err != nil {
     fmt.Println("error decoding json:", err)
     return
     }
    
     fmt.Println(post)
    }
    

    삽입식 struct의 서열화
    Go는 nested struct의 시리얼화 및 역시리얼화를 지원합니다.
    type App struct {
     Id string `json:"id"`
    }
    
    type Org struct {
     Name string `json:"name"`
    }
    
    type AppWithOrg struct {
     App
     Org
    }
    
    func main() {
     data := []byte(`
     {
     "id": "k34rAT4",
     "name": "My Awesome Org"
     }
     `)
    
     var b AppWithOrg
    
     json.Unmarshal(data, &b)
     fmt.Printf("%#v", b)
    
     a := AppWithOrg{
     App: App{
     Id: "k34rAT4",
     },
     Org: Org{
     Name: "My Awesome Org",
     },
     }
     data, _ = json.Marshal(a)
     fmt.Println(string(data))
    }
    

    Nested struct는 좀 이상하게 보이지만 가끔 유용할 때가 있다.
    사용자 정의 시리얼화 함수
    Go JSON package에는 두 개의 Interface Marshaler와 Unmarshaler가 있습니다. 이 두 개의 Interface는 당신이 정의한 type에서 서열화 작업을 지원할 수 있습니다.
    오류 처리
    항상 시퀀스나 반정렬화된 오류를 검사하는 것을 기억하면 오류가 발생한 후에 오류를 가지고 계속 실행하는 것이 아니라 프로그램을 더욱 튼튼하게 할 수 있다.

    좋은 웹페이지 즐겨찾기