Go 语言神奇的 JSON

Posted 51reboot运维开发

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go 语言神奇的 JSON相关的知识,希望对你有一定的参考价值。

15


今天我想和大家分享 Go 语言一些非常实用的技巧,用于编码和解码 JSON 文档。Go 语言的 encoding/json 包有一些有趣的特性,帮助我们轻松地解析 JSON 文档。你可以轻松地将大多数实际应用中的 JSON 转换为带有 Go 语言结构体标签的接口或者是 MarshalerUnmarshaler 接口。


但有一个案例比较棘手:包含转义 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


公告通知

Golang 班、架构师班、自动化运维班正在招生中

各位小伙伴们,欢迎试听和咨询:

QQ(1):979950755    小月   

QQ(2):279312229    ada   

WeChat : 1902433859   小月

WeChat : 1251743084   小单


技术交流群:

  • Golang 技术交流群 426582602

  • Python 交流群 365534424 / 238757010


详情点击【阅读原文】即可跳转

以上是关于Go 语言神奇的 JSON的主要内容,如果未能解决你的问题,请参考以下文章

Go语言JSON 处理

你知道的Go切片扩容机制可能是错的

神奇的 Go init 函数

go语言之玩味json

怎么学习golang

Go 语言中的动态 JSON