在开发应用程序时,客户端(前端页面或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的解析和生成两个方面。
- 解析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)
}
- 生成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序列化和反序列化逻辑。
- 自定义序列化:可以在结构体类型上定义
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)"}
- 自定义反序列化:可以在结构体类型上定义
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数据(比如从一个文件读取),那么用Encoder和Decoder会更方便。
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接口的参数,也就是说Decoder从io.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处理可以按照以下步骤进行:
-
了解JSON的基本概念:JSON(JavaScript Object Notation)是一种用于数据交换的轻量级数据格式,它基于JavaScript语言的一个子集。首先,了解JSON的基本语法和数据类型,包括对象、数组、字符串、数字、布尔值和null等。
-
学习Go语言中的JSON包:Go语言提供了
encoding/json包来处理JSON数据。掌握encoding/json包中的常用函数和类型,例如json.Marshal()、json.Unmarshal()、json.Encoder和json.Decoder等。 -
解析JSON数据:学习如何将JSON字符串解析为Go语言中的数据结构,包括结构体、切片、映射等。了解如何使用
json.Unmarshal()函数进行解析,并学会处理解析过程中可能出现的错误。 -
生成JSON数据:学习如何将Go语言中的数据结构转换为JSON字符串。掌握如何使用
json.Marshal()函数进行序列化,并了解如何自定义JSON的编码方式。 -
处理复杂JSON数据:学习处理包含嵌套结构和多层级数据的复杂JSON。了解如何使用嵌套结构体或者映射来表示复杂的JSON结构,并学习如何递归地解析和生成复杂JSON数据。