Go 語言神奇的 JSON

今天我想和大家分享 Go 語言一些非常實用的技巧,用於編碼和解碼 JSON 文檔。Go 語言的 encoding/json 包有一些有趣的特性,幫助我們輕鬆地解析 JSON 文檔。你可以輕鬆地將大多數實際應用中的 JSON 轉換爲帶有 Go 語言結構體標籤的接口或者是 Marshaler 和 Unmarshaler 接口。

但有一個案例比較棘手:包含轉義 JSON 元素的 JSON 文檔。如下所示:

{
   "id": 12345,
   "name": "Test Document",
   "payload": "{\"message\":\"hello!\"}"
}

我不建議構建像這樣創建文檔的應用程序,但有時候這樣的情況是難以避免的,你希望像平常的 JSON 那樣,一步就能解析這個文檔。也許你從如下兩種類型開始:

type LogEntry struct {
   ID      int    `json:"id"`
   Name    string `json:"name"`
   Payload string `json:"payload"`
}
type LogPayload struct {
   Message string `json:"message"`
}

Matt Holt 的 json-to-go 能夠幫助你從 JSON 示例中生成初始結構體,不妨試一下!

首先要將 LogEntry.Payload 的類型從 string 類型改爲 LogPayload 類型。這點很重要,因爲這是你最終想要得到的,這就是 encoding/json 包處理該元素的方式。現在的問題是 payload 元素的實際入站類型是一個 JSON 字符串。你需要在 LogPayload 類型上實現 Unmarshaler 接口,並將其解碼爲字符串,然後再解碼爲 LogPayload 類型。

func (lp *LogPayload) UnmarshalJSON(b []byte) error {
   var s string
   if err := json.Unmarshal(b, &s); err != nil {
       return err
   }
   if err := json.Unmarshal([]byte(s), lp); err != nil {
       return err
   }

   return nil
}

看起來很棒,然而不幸的是第二個 json.Unmarshal 調用將會導致調用堆棧的遞歸。你需要將它解碼成一箇中間類型,你可以通過定義一個帶有 LogPayload 基礎類型的新類型來實現,例如這樣:

type fauxLogPayload LogPayload

你可以將上面的代碼調整一下,將其解碼爲 fauxLogPayload 類型,然後將結果轉換爲 LogPayload 類型。

func (lp *LogPayload) UnmarshalJSON(b []byte) error {
   var s string
   if err := json.Unmarshal(b, &s); err != nil {
       return err
   }
   var f fauxLogPayload
   if err := json.Unmarshal([]byte(s), &f); err != nil {
       return err
   }

   *lp = LogPayload(f)

   return nil
}

現在,要解析整個文檔的調用站點變得更好了,也簡潔了:

func main() {
   doc := []byte(`{
       "id": 12345,
       "name": "Test Document",
       "payload": "{\"message\":\"test\"}"
   }`)
   var entry LogEntry
   if err := json.Unmarshal(doc, &entry); err != nil {
       fmt.Println("Error!", err)
   }
   fmt.Printf("%v", entry)
}

你可以在 Go Playground 找到這些代碼。

我希望這個例子說明了 Go 語言可以多麼容易地將對 encoding/decoding 的關注點從業務邏輯中分離出來。你可以在任何時候使用此方法將基本 JSON 類型轉換爲更復雜的用戶定義類型。

Cheers!

感謝 Redditors BubuX 和 quiI ,他們建議鏈接到 JSON -to- Go ,並在 main.go 中爲我的 JSON 使用 Go 語言的字符串文字。

原文鏈接: https://medium.com/@turgon/json-in-go-is-magical-c5b71505a937
譯文鏈接:https://studygolang.com/articles/12619
作者:turgon 譯者:SergeyChang 校對:rxcai

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章