写点什么

Go 语言快速入门指南:Go 语言解析 JSON

作者:宇宙之一粟
  • 2022 年 1 月 13 日
  • 本文字数:3577 字

    阅读完需:约 12 分钟

Go 语言快速入门指南:Go 语言解析JSON

本文将说明如何利用 Go 语言将 JSON 解析为结构体和数组,如果解析 JSON 的嵌入对象,如何将 JSON 的自定义属性名称映射到结构体,如何解析非结构化的 JSON 字符串。

JSON 解析为结构体

JSON 的结构是 key-value,最直观的就是将 JSON 解析为结构体,如下 JSON :


{  "name": yuzhou1u,  "age": 18}
复制代码


Go 语言中,提供了一个专门的包 encoding/json ,所以我们在使用这个 JSON 包之前需要在头文件导入:


package main
import ( "encoding/json" "fmt")
复制代码


然后,我们需要定义一个 Go 语言的结构体以便我们能与 JSON 一一对应,比如在 JSON 中我们定义了姓名 name 和年龄 age ,所以需要定义一个结构体(命名可以随意,但最好通俗易懂)的字段与 JSON 字符串中的键相匹配:


type Person struct {  Name string  Age int}
复制代码


然后使用 json.Umarshal() 函数来解析 JSON 字符串,完整代码如下:


package main
import ( "encoding/json" "fmt")
type Person struct { Name string Age int}
func main() { var p Person
jsonString := `{"name": "yuzhou1su", "age" : 18}`
err := json.Unmarshal([]byte(jsonString), &p)
if err == nil { fmt.Println(p.Name) fmt.Println(p.Age) } else { fmt.Println(err) }
}
复制代码


现在来解释一下上面 main 函数的代码:


  • 定义一个 Person 的 p 对象

  • 因为我们没有把文件系统使用上,所以是定义了一个 jsonString的 JSON 数据

  • 使用 json.Unmarshal() 函数能够解析 JSON 格式的数据。但需要将 JSON 字符串转换为字节切片,并将结果存储到 p 对象中。 使用需要使用 & 地址运算符传入人员的地址。

  • 如果解析有效,则 json.Unmarshal() 函数返回 nil,您现在可以找到存储在 person 变量中的值。

  • 确保将 Person 结构中每个字段的第一个字符大写。 如果字段名称以小写字母开头,则不会导出到当前包之外,并且字段对 json.Unmarshal() 函数不可见。


运行上述代码,打印在控制台中结果为:


yuzhou1su18
复制代码

JSON 解析为数组

通常 JSON 数据会包括一系列的对象数组,就像这样一个班级的数据:


[  {    "id": 1,    "name": "张三"    "age": 20  },  {    "id": 2,    "name": "李翠花"    "age": 18  },  {    "id": 3,    "name": "王老五"    "age": 25  }]
复制代码


我们只需要定义一个 students[] 的数组,代码如下:


package main
import ( "encoding/json" "fmt")
type Student struct { Id int Name string Age int}
func main() {
var students []Student myClass := `[ { "id": 1, "name": "张三", "age": 20 }, { "id": 2, "name": "李翠花", "age": 18 }, { "id": 3, "name": "王老五", "age": 25 } ]`
err := json.Unmarshal([]byte(myClass), &students)
if err == nil { for _, student := range students { fmt.Print("\t\n", student.Id) fmt.Print("\t", student.Name) fmt.Print("\t", student.Age) } } else { fmt.Println(err) }}
复制代码


使用 for...range 迭代数组,然后运行上述代码:


$ go run main.go
1 张三 202 李翠花 183 王老五 25
复制代码

解析 JSON 嵌入对象

JSON 字符串有时包含嵌入对象,比如:


{  "name": "yuzhou1su",  "age": 18,  "address": {    "road": "renmin south road",    "street": "123 street",    "city": "cs",    "province": "hn",    "country": "cn"  }}
复制代码


address 就是属于内嵌对象,我们同样需要创建另一个 Address 结构体:


package main
import ( "encoding/json" "fmt")
type Person struct { Name string Age int Address struct { Road string Street string City string Province string Country string }}
func main() { var p Person
jsonString := ` { "name": "yuzhou1su", "age": 18, "address": { "road": "renmin south road", "street": "123 street", "city": "cs", "province": "hn", "country": "cn" } }`
err := json.Unmarshal([]byte(jsonString), &p)
if err == nil { fmt.Println(p.Name) fmt.Println(p.Age) fmt.Println(p.Address.Road) fmt.Println(p.Address.Street) fmt.Println(p.Address.City) fmt.Println(p.Address.Province) fmt.Println(p.Address.Country) } else { fmt.Println(err) }
}
复制代码


输出结果:


yuzhou1su18renmin south road123 streetcshncn
复制代码

自定义属性名称的映射

有时 JSON 字符串中的键不能直接映射到 Go 中结构的成员。 比如:


{  "base currency": "USD",  "destination currency": "CNY"}
复制代码


请注意,此 JSON 字符串中的键中有空格。 如果你尝试将它直接映射到一个结构,你会遇到问题,因为 Go 中的变量名不能有空格。 要解决此问题,您可以使用结构字段标记(在结构中的每个字段之后放置的字符串文字),如下所示:


type Rates stuct {  Base string `json:"base currency"`  Symbol string `json:"destination currency"`}
复制代码


  • JSON 的 base currency 映射到 Go 中的 Base 字段

  • JSON 的 destination currency 映射到 Go 中 Symbol


整合如下:


package main
import ( "encoding/json" "fmt")
type Rates struct { Base string `json:"base currency"` Symbol string `json:"destination currency"`}
func main() {
jsonString := ` { "base currency": "USD", "destination currency": "CNY" }`
var rates Rates err := json.Unmarshal([]byte(jsonString), &rates)
if err == nil { fmt.Println(rates.Base) fmt.Println(rates.Symbol) } else { fmt.Println(err) }
}
复制代码


运行如下代码:


$ go run main.goUSDCNY
复制代码

非结构化数据的映射

前面几节展示了相对简单的 JSON 字符串。 然而,在现实世界中,您要操作的 JSON 字符串通常很大且非结构化。 此外,您可能只需要从 JSON 字符串中检索特定值。


考虑以下 JSON 字符串:


{    "success": true,    "timestamp": 1588779306,    "base": "USD",    "date": "2022-01-15",    "rates": {        "BNB": 0.00225,        "BTC": 0.000020,        "EUR": 0.879,        "GBP": 0.733,        "CNY": 6.36    } }
复制代码


如果我们还想把美元解析为其他币种,不至于重新定义整个结构体,可以采取定义一个接口:


var result map[string] interface{}
复制代码


上面的语句创建了一个 map 类型的变量 result,它的 key 是 string 类型,每个对应的 value 都是 interface{} 类型。 这个空接口表示该值可以是任何类型:


为了解析这个 JSON 字符串,我们应该使用 json.Unmarshal() 函数:


json.Unmarshal([]byte(jsonString), &result)
复制代码


因为 result 的类型是接口,所有可以传入任何类型:


  • 当解析 success 键的话可以使用 result["sucess"],解析为布尔型。

  • 当解析 timestamp 时可以解析为数字类型

  • 解析 rates 使用传入 rates 即可, 即 rates := result["rates"],解析为 map 类型


整个代码如下:


package main
import ( "encoding/json" "fmt")
type Rates struct { Base string `json:"base currency"` Symbol string `json:"destination currency"`}
func main() {
jsonString := ` { "success": true, "timestamp": 1588779306, "base": "USD", "date": "2022-01-15", "rates": { "BNB": 0.00225, "BTC": 0.000020, "EUR": 0.879, "GBP": 0.733, "CNY": 6.36 } }`
var result map[string]interface{} err := json.Unmarshal([]byte(jsonString), &result) if err == nil { fmt.Println(result["success"]) rates := result["rates"] fmt.Println(rates) } else { fmt.Println(err) }
}
复制代码


运行代码如下:


$ go run main.gotruemap[BNB:0.00225 BTC:2e-05 CNY:6.36 EUR:0.879 GBP:0.733]
复制代码

总结

JSON 数据作为常见的数据格式,有着非常多的使用场景。本篇文章介绍了如何利用 Go 语言来解析 JSON 数据,如解析为结构体、数组、嵌入对象,解析自定义字段和解析非结构化数据。下一篇文章将介绍一下如果将 Go 语言的数据编码为 JSON 数据,敬请期待!

发布于: 刚刚阅读数: 3
用户头像

宇宙古今无有穷期,一生不过须臾,当思奋争 2020.05.07 加入

🏆InfoQ写作平台-第二季签约作者 🏆 混迹于江湖,江湖却没有我的影子 热爱技术,专注于后端全栈,轻易不换岗 拒绝内卷,工作于软件工程师,弹性不加班 热衷分享,执着于阅读写作,佛系不水文

评论

发布
暂无评论
Go 语言快速入门指南:Go 语言解析JSON