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

JSON 解析为构造体

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

{  "name": yuzhou1u,  "age": 18}

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

package mainimport (  "encoding/json"  "fmt")

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

type Person struct {  Name string  Age int}

而后应用 json.Umarshal() 函数来解析 JSON 字符串,残缺代码如下:

package mainimport (  "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 mainimport (  "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.go1  张三  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 mainimport (  "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 mainimport (  "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 mainimport (  "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 数据,敬请期待!