Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Go语言JSON序列化与反序列化

Go语言JSON 序列化与反序列化的实现

作者:jieyucx

在Go语言中,通过encoding/json标准库实现结构体与JSON之间的相互转换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

在编程里,不同语言(Go、Java、Python、前端JS)要互相传递数据,必须用一种大家都认识的通用格式
JSON 就是目前全世界最流行、最简单、最通用的格式。
本文从JSON 底层本质、数据类型、语法规则讲起,再到 Go 序列化/反序列化完整实战,包含字节级转换、内存地址变化、标签细节、易错点、底层原理,零基础可直接看懂、直接复制运行。

一、什么是 JSON?(最直白解释)

JSON = JavaScript Object Notation
你不用管英文全称,只需要记住一句话:

JSON 本质就是一段有固定格式的纯文本字符串,用来存储和传输数据。

它的特点:

小知识点:JSON 不是对象、不是结构体,只是字符串,程序拿到后解析成对应语言的对象。

二、JSON 支持哪些数据类型?(必须背下来)

JSON 一共只支持 6 种数据类型,没有第七种!
不支持日期、函数、正则、undefined 等类型。

  1. 对象(Object) → 用 { }
  2. 数组(Array) → 用 [ ]
  3. 字符串(String)
  4. 数字(Number)
  5. 布尔值(true / false)
  6. 空值(null)

三、JSON 6 种数据类型详解(带例子+细节注意)

1. 对象(Object)

例子:

{
  "name": "Alice",
  "age": 18,
  "isStudent": true
}

2. 数组(Array)

例子:

[10, 20, 30, 40]

对象数组(最常用):

[
  { "name": "Alice" },
  { "name": "Bob" }
]

3. 字符串(String)

正确:

"name": "Alice"

错误:

"name": 'Alice'  // 错!JSON 不支持单引号

4. 数字(Number)

"age": 18,
"score": 95.5,
"temperature": -5

5. 布尔值(true / false)

"isStudent": true

6. 空值 null

"remark": null

小细节:null≠"",反序列化时 Go 中 nil 对应 JSON null,"" 是空字符串。

四、JSON 必须遵守的规则(注意点!错一个就解析失败)

  1. key 必须用英文双引号,不能单引号、不加引号
  2. 字符串必须英文双引号
  3. 不能有多余逗号:最后一个键值对/数组元素后不能加逗号
  4. 不能写注释:// 单行注释、/* */ 多行注释都不支持
  5. 严格大小写敏感:Name 和 name 是两个完全不同的 key
  6. 符号全部用英文半角符号:逗号、冒号、括号,不能用中文符号
  7. 只支持上面 6 种数据类型,不支持其他类型

五、一个标准完整的 JSON 例子(包含所有类型+嵌套)

{
  "name": "Alice",
  "age": 18,
  "score": 95.5,
  "isPass": true,
  "hobbies": ["read", "run"],
  "class": {
    "className": "Class One"
  },
  "remark": null
}

包含:对象、数组、字符串、数字、布尔、null、嵌套结构,是实际开发最常见格式。

六、现在进入 Go 部分:什么是序列化、反序列化?

核心底层理解

1. 序列化(Marshal)

Go 内存数据 → JSON 字符串(字节数组)
作用:把 Go 里的数据转成 JSON,用于网络传输、接口返回、文件存储。

2. 反序列化(Unmarshal)

JSON 字符串 → Go 内存数据
作用:把接收的 JSON 解析成 Go 程序能直接操作的结构体、切片。

关键知识点:序列化/反序列化是数据拷贝,不是引用,转换后内存地址完全不同。

七、Go 操作 JSON 的基础包

Go 自带标准库,无需安装第三方依赖,开箱即用:

import "encoding/json"

小知识点:json.Marshal 返回 []byte 字节数组,不是字符串,需要用 string() 转换。

八、超级清晰底层示例:英文切片序列化(字节级+内存地址对照)

使用纯英文数据,可清晰看到字节数字 ↔ JSON 字符一一对应,直观理解 JSON 本质。

完整可运行代码

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	// -------------- 第一步:原始 Go 切片(纯英文) --------------
	students := []string{"Alice", "Bob", "Charlie"}
	fmt.Println("Original Go Slice:", students)
	fmt.Printf("Original Slice Memory Address: %p\n\n", &students)

	// -------------- 第二步:序列化 → JSON 字节数组 --------------
	jsonBytes, err := json.Marshal(students)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	// 打印ASCII字节数组(数字对应JSON字符)
	fmt.Println("Serialized JSON Bytes (ASCII Code):", jsonBytes)
	// 字节数组转字符串 = 标准JSON
	fmt.Println("Bytes Converted To String (JSON):", string(jsonBytes))
	fmt.Printf("JSON Bytes Array Memory Address: %p\n\n", &jsonBytes)

	// -------------- 第三步:反序列化 → 新的 Go 切片 --------------
	var newStudents []string
	err = json.Unmarshal(jsonBytes, &newStudents)

	fmt.Println("Deserialized Go Slice:", newStudents)
	fmt.Printf("New Slice Memory Address: %p\n\n", &newStudents)

	// -------------- 第四步:遍历打印 --------------
	fmt.Println("==== Iterate Over Deserialized Slice ====")
	for index, value := range newStudents {
		fmt.Printf("Index %d → Value: %s\n", index, value)
	}
}

真实运行结果+ASCII对照

Original Go Slice: [Alice Bob Charlie]
Original Slice Memory Address: 0x140000a0000

Serialized JSON Bytes (ASCII Code): [91 34 65 108 105 99 101 34 44 34 66 111 98 34 44 34 67 104 97 114 108 105 101 34 93]
Bytes Converted To String (JSON): ["Alice","Bob","Charlie"]
JSON Bytes Array Memory Address: 0x140000a4000

Deserialized Go Slice: [Alice Bob Charlie]
New Slice Memory Address: 0x140000a0010

==== Iterate Over Deserialized Slice ====
Index 0 → Value: Alice
Index 1 → Value: Bob
Index 2 → Value: Charlie

ASCII 数字 ↔ 字符精准对应

91 → [
34 → "
65 → A
108 → l
105 → i
99 → c
101 → e
34 → "
44 → ,
93 → ]

核心结论:JSON 底层就是ASCII 字节数字,转成字符串后就是我们看到的 JSON 格式;转换前后内存地址不同,是全新数据。

九、Go 结构体转 JSON(序列化)

第一步:定义结构体(关键细节必看)

强制规则:结构体字段必须首字母大写!

同时支持嵌套结构体,完全对应 JSON 嵌套对象。

package main

import (
	"encoding/json"
	"fmt"
)

// 班级结构体(嵌套用)
type Class struct {
	ClassName string
}

// 学生主结构体
type Student struct {
	Name      string      // 姓名
	Age       int         // 年龄
	Score     float64     // 分数
	IsPass    bool        // 是否及格
	Hobbies   []string    // 爱好(切片→JSON数组)
	Class     Class       // 班级(嵌套结构体→JSON嵌套对象)
	Remark    interface{} // 备注(可存nil→JSON null)
}

第二步:序列化完整代码+输出

func main() {
	stu := Student{
		Name:    "Alice",
		Age:     18,
		Score:   95.5,
		IsPass:  true,
		Hobbies: []string{"read", "run"},
		Class:   Class{"Class One"},
		Remark:  nil,
	}

	// 普通序列化(紧凑一行)
	jsonBytes, _ := json.Marshal(stu)
	fmt.Println("Compact JSON:")
	fmt.Println(string(jsonBytes))

	// 格式化序列化(带换行缩进,便于阅读,开发调试常用)
	jsonIndentBytes, _ := json.MarshalIndent(stu, "", "  ")
	fmt.Println("\nPretty JSON:")
	fmt.Println(string(jsonIndentBytes))
}

输出结果

紧凑版:

{"Name":"Alice","Age":18,"Score":95.5,"IsPass":true,"Hobbies":["read","run"],"Class":{"ClassName":"Class One"},"Remark":null}

格式化版:

{
  "Name": "Alice",
  "Age": 18,
  "Score": 95.5,
  "IsPass": true,
  "Hobbies": [
    "read",
    "run"
  ],
  "Class": {
    "ClassName": "Class One"
  },
  "Remark": null
}

小知识点:json.MarshalIndent(对象, 前缀, 缩进),第二个参数是行前缀,第三个是缩进空格。

十、JSON 转 Go 结构体(反序列化)

核心强制规则:必须传结构体地址&stu

func main() {
	// 标准JSON字符串
	jsonStr := `{
		"Name":"Alice",
		"Age":18,
		"Score":95.5,
		"IsPass":true,
		"Hobbies":["read","run"],
		"Class":{"ClassName":"Class One"},
		"Remark":null
	}`

	// 定义空结构体接收数据
	var stu Student

	// 反序列化:必须传 &stu
	err := json.Unmarshal([]byte(jsonStr), &stu)
	if err != nil {
		fmt.Println("反序列化失败:", err)
		return
	}

	fmt.Printf("反序列化结果:%+v\n", stu)
}

十一、JSON 标签(开发必备·细节全解)

Go 结构体字段默认大写,前端接口规范常用小写,通过 json:"标签" 自定义 JSON 行为,三种核心用法:

1. 自定义 JSON 键名(最常用)

type Student struct {
	Name  string `json:"name"`  // JSON中key为小写name
	Age   int    `json:"age"`
	Score int    `json:"score"`
}

输出:{"name":"Alice","age":18,"score":95}

2. 忽略字段:json:"-"

该字段不参与序列化,不会出现在 JSON 中,用于密码、内部标识等敏感字段:

Pwd string `json:"-"` // 序列化直接忽略

3. 空值不输出:omitempty

字段值为默认零值(""0falsenil)时,JSON 中不显示该字段:

Score int `json:"score,omitempty"`

细节:omitempty 只作用于序列化,反序列化不受影响。

完整标签示例

type Student struct {
	Name  string `json:"name"`
	Age   int    `json:"age,omitempty"`
	Pwd   string `json:"-"`
}

十二、最常见错误总结(必看+细节原因)

  1. 结构体字段小写:外部包无法访问,字段丢失
  2. JSON 使用单引号/中文符号:语法错误,解析直接失败
  3. JSON 最后字段加逗号:严格语法校验报错
  4. 反序列化不传地址 &:值拷贝,无法赋值,结果为空
  5. JSON key 与结构体不匹配:用 json:"xxx" 标签映射
  6. JSON 写注释:JSON 不支持注释,解析失败
  7. 混淆 null 和空字符串:nil 对应 null,"" 是空字符串

十三、最终总结(超清晰·重点提炼)

  1. JSON 本质:一段带格式的纯文本字符串,底层是字节数组(ASCII 数字)
  2. JSON 6 种数据类型:对象、数组、字符串、数字、布尔、null,无其他类型
  3. JSON 语法铁律:双引号、英文符号、无注释、无尾逗号、大小写敏感
  4. Go 依赖标准库 encoding/json,无需第三方包
  5. 序列化:Go 内存数据 → JSON 字符串;反序列化:JSON → Go 内存数据
  6. 转换是数据拷贝,内存地址变化,不是引用
  7. 结构体字段必须大写才能被 json 包识别
  8. json:"标签" 自定义键名、忽略字段、空值隐藏,适配前端接口规范

到此这篇关于Go语言JSON 序列化与反序列化的实现的文章就介绍到这了,更多相关Go语言JSON序列化与反序列化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文