GO语言入门指南:Go的JSON操作 | 青训营

70 阅读6分钟

在开发应用程序时,客户端(前端页面或APP)与服务端交互是在所难免的,在交互过程传递数据时,最通用和流行格式便是JSON,Go语言提供了encoding/json包,用于处理JSON数据的编码与解码。

JSON简介

什么是JSON?

JSON的全称是Javascript Object Notation,是一种数据结构化交互的标准协议,非常容易阅读与编写,可以作为配置文件保存应用的相关配置信息,也可以作为前后端接口数据的格式,比如后端返回给前端这样的JSON数据:

{
 "code":404,
 "msg":"Not Found"
}

JSON的数据类型

JSON只支持六种数据类型,分别是:

  • 数字(number):有十进制和科学记数学两种表示方式。
  • 字符串(string):使用双引号表示的Unicode字符序列。
  • 布尔(bool)true或者false
  • 对象(object):使用花括号({})括起来的一个或多个键值对(key/value),用逗号(,)隔开,最后一个键值对后面不能有逗号,键(key)必是双引号("")引起来的字符串,而值则可以是任意类型(如:布尔、数字、对象、数组、字符串)。
  • 数组(array):使用中括号([])括起来的值的集合,这些值可是任意类型(布尔、数字、对象、数组、字符串)。
  • null:空值。

JSON类型与Go数据类型的对应关系:

  • Go的boolean对应JSON的bool类型
  • Go的整型与浮点型对应JSON的number类
  • Go的map和struct对应JSON的object,map的key必须是字符串
  • Go的切片与数组对应JSON的array
  • Go的chan与函数等复杂的类型不能作为JSON的值

JSON的基本操作

Go语言在encoding/json包中提供了JSON数据序列化与反序列化的操作,最简单直接就是调用Marshal把一个Go的数据序列化为一个JSON数据和调用Unmarshal对JSON数据反序列化。 Go语言中的JSON基本操作涉及到JSON的解析和生成两个方面。

  1. 解析JSON:使用encoding/json包来解析JSON字符串。可以使用json.Unmarshal()函数将JSON字符串解析为Go语言中的结构体或者Map类型。
package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	jsonStr := `{"name":"Alice","age":20}`
	
	var person Person
	err := json.Unmarshal([]byte(jsonStr), &person)
	if err != nil {
		fmt.Println("JSON解析失败:", err)
		return
	}

	fmt.Println("姓名:", person.Name)
	fmt.Println("年龄:", person.Age)
}
  1. 生成JSON:使用encoding/json包来生成JSON字符串。可以使用json.Marshal()函数将Go语言中的结构体或者Map类型转换为JSON字符串。
package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	person := Person{
		Name: "Alice",
		Age:  20,
	}

	jsonBytes, err := json.Marshal(person)
	if err != nil {
		fmt.Println("JSON生成失败:", err)
		return
	}

	jsonStr := string(jsonBytes)
	fmt.Println("生成的JSON字符串:", jsonStr)
}

自定义序列化

在Go语言中,可以通过自定义结构体的MarshalJSON()UnmarshalJSON()方法来实现自定义的JSON序列化和反序列化逻辑。

  1. 自定义序列化:可以在结构体类型上定义MarshalJSON()方法,该方法会在结构体对象被转换为JSON字符串时被调用。在该方法中,可以自定义需要输出的JSON字段和值。
package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string
	Age  int
}

func (p Person) MarshalJSON() ([]byte, error) {
	// 自定义输出的JSON字段和值
	data := map[string]interface{}{
		"fullname": fmt.Sprintf("%s (%d years old)", p.Name, p.Age),
	}

	// 使用json.Marshal将data转换为JSON字符串
	return json.Marshal(data)
}

func main() {
	person := Person{
		Name: "Alice",
		Age:  20,
	}

	jsonBytes, err := json.Marshal(person)
	if err != nil {
		fmt.Println("JSON生成失败:", err)
		return
	}

	jsonStr := string(jsonBytes)
	fmt.Println("生成的JSON字符串:", jsonStr)
}

输出结果:

生成的JSON字符串: {"fullname":"Alice (20 years old)"}
  1. 自定义反序列化:可以在结构体类型上定义UnmarshalJSON(data []byte) error方法,该方法会在JSON字符串被转换为结构体对象时被调用。在该方法中,可以自定义解析JSON字段和值的逻辑。
package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string
	Age  int
}

func (p *Person) UnmarshalJSON(data []byte) error {
	// 自定义解析JSON字段和值的逻辑
	var jsonData map[string]interface{}
	err := json.Unmarshal(data, &jsonData)
	if err != nil {
		return err
	}

	// 提取需要的字段并进行类型转换
	name, ok := jsonData["fullname"].(string)
	if !ok {
		return fmt.Errorf("解析fullname字段失败")
	}
	age := 0
	fmt.Sscanf(name, "%s (%d years old)", &p.Name, &age)
	p.Age = age

	return nil
}

func main() {
	jsonStr := `{"fullname":"Alice (20 years old)"}`

	var person Person
	err := json.Unmarshal([]byte(jsonStr), &person)
	if err != nil {
		fmt.Println("JSON解析失败:", err)
		return
	}

	fmt.Println("姓名:", person.Name)
	fmt.Println("年龄:", person.Age)
}

输出结果:

姓名: Alice
年龄: 20

通过自定义MarshalJSON()UnmarshalJSON()方法,可以灵活地控制结构体对象与JSON字符串之间的转换逻辑。

Encoder与Decoder

调用Marshal只会返回一个字节数组,Unmarshal函数只能传入一个字节数组,如果我们想将序列化的数据写入到不同的地方(比如保存到一个文件中),或者想从不同地方读取JSON数据(比如从一个文件读取),那么用EncoderDecoder会更方便。

json.Encoder

NewEncoder函数可以创建一个Encoder结构体,NewEncoder函数接收一个实现了io.Writer接口的参数,在序列化后会调用io.Writer写入数据:

package main

import (
 "encoding/json"
 "os"
)

func main() {
 m := map[string]int{"Go入门"1"Go Ation"2"Go从入门到精通"3"Go高级编程"4}
 file, err := os.Create("config.json")
 if err != nil {
  panic(err)
 }
    defer file.Close()
 encoder := json.NewEncoder(file)
 encoder.SetIndent("""\t")
 err = encoder.Encode(m)

 if err != nil {
  panic(err)
 }
}

上面程序运行后,会把JSON数据保存到当前目录的config.json文件当中。

json.Decoder

NewDecoder函数可以创建一个Decoder结构体,NewDecoder函数接收一个实现了io.Reader接口的参数,也就是说Decoderio.Reader中读取数据:

package main

import (
 "encoding/json"
 "fmt"
 "os"
)

func main() {
 file, err := os.Open("config.json")
 if err != nil {
  panic(err)
 }
 defer file.Close()
 decoder := json.NewDecoder(file)
 var m map[string]int
 err = decoder.Decode(&m)
 if err != nil {
  panic(err)
 }
 fmt.Println(m)
}

小结

JSON是一种非常通用的数据格式,经常被用于前后端api接口的数据通信,而Go语言在标准库encoding/json包中为JSON数据的编码与反编码提供非常好的支持。

学习Go语言中的JSON处理可以按照以下步骤进行:

  1. 了解JSON的基本概念:JSON(JavaScript Object Notation)是一种用于数据交换的轻量级数据格式,它基于JavaScript语言的一个子集。首先,了解JSON的基本语法和数据类型,包括对象、数组、字符串、数字、布尔值和null等。

  2. 学习Go语言中的JSON包:Go语言提供了encoding/json包来处理JSON数据。掌握encoding/json包中的常用函数和类型,例如json.Marshal()json.Unmarshal()json.Encoderjson.Decoder等。

  3. 解析JSON数据:学习如何将JSON字符串解析为Go语言中的数据结构,包括结构体、切片、映射等。了解如何使用json.Unmarshal()函数进行解析,并学会处理解析过程中可能出现的错误。

  4. 生成JSON数据:学习如何将Go语言中的数据结构转换为JSON字符串。掌握如何使用json.Marshal()函数进行序列化,并了解如何自定义JSON的编码方式。

  5. 处理复杂JSON数据:学习处理包含嵌套结构和多层级数据的复杂JSON。了解如何使用嵌套结构体或者映射来表示复杂的JSON结构,并学习如何递归地解析和生成复杂JSON数据。