今天我想和大家分享 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