一、JSON 基础概念
- JSON 全称:JavaScript Object Notation,轻量级数据交换格式
- 特性:跨平台、跨语言、可读性强,前后端 / 服务间通用数据传输标准
- Go 操作 JSON 标准库:
encoding/json - Go 处理 JSON 两种核心方案:
- 结构体 struct:结构固定、类型安全,推荐业务开发使用
- map string interface {}:结构动态、适配未知 JSON 字段
二、核心前置规则(必记踩坑点)
- 结构体字段首字母必须大写 小写字段为包内私有,
json.Marshal无法反射读取,会直接忽略该字段。 - 结构体标签
struct tag控制 JSON 输出规则 - 反序列化
json.Unmarshal第二个参数必须传变量地址,否则修改无效 - map 解析 JSON 后所有数值默认类型为
float64,数组为[]interface{},需要类型断言取值
三、通过结构体生成 JSON(序列化 Marshal)
3.1 基础无标签示例
go
Go
package main
import (
"encoding/json"
"fmt"
)
// IT 行业信息结构体
type IT struct {
Company string
Subjects []string
IsOk bool
Price float64
}
func main() {
// 结构体实例赋值
s := IT{
Company: "itcast",
Subjects: []string{"Go", "C++", "Python", "Test"},
IsOk: true,
Price: 666.666,
}
// json.Marshal:结构体 → JSON字节流
buf, err := json.Marshal(s)
if err != nil {
fmt.Println("序列化失败 err = ", err)
return
}
// 字节切片转字符串打印
fmt.Println("JSON结果 = ", string(buf))
}
输出结果:
plaintext
Go
JSON结果 = {"Company":"itcast","Subjects":["Go","C++","Python","Test"],"IsOk":true,"Price":666.666}
3.2 struct tag 标签语法详解(重点)
标签格式:json:"自定义key,附加选项"
表格
| 标签写法 | 作用说明 |
|---|---|
json:"-" |
忽略此字段,不序列化输出到 JSON |
json:"subjects" |
自定义 JSON 字段名(二次命名,统一前后端小写命名规范) |
json:",string" |
将数字 / 布尔值序列化为字符串格式输出 |
带标签完整结构体示例:
go
Go
type IT struct {
Company string `json:"-"` // 忽略该字段
Subjects []string`json:"subjects"` // 自定义json key
IsOk bool `json:",string"` // bool转字符串
Price float64 `json:",string"` // 浮点数转字符串
}
四、通过 map 生成 JSON(动态结构序列化)
适合字段不固定、无法提前定义结构体的场景,使用 map[string]interface{} 存储任意类型值
go
Go
package main
import (
"encoding/json"
"fmt"
)
func main() {
// 创建map,预分配4个空间
m := make(map[string]interface{}, 4)
m["company"] = "itcast"
m["subjects"] = []string{"GO", "C++", "Python", "Test"}
m["isok"] = true
m["price"] = 666.666
// map序列化
result, err := json.Marshal(m)
if err != nil {
fmt.Println("序列化失败 err = ", err)
return
}
fmt.Println("map转JSON = ", string(result))
}
五、JSON 反序列化 Unmarshal:JSON → Go 变量
5.1 JSON 解析到结构体(固定结构首选)
流程:JSON 字符串转[]byte → 传入json.Unmarshal,传入结构体地址
go
Go
package main
import (
"encoding/json"
"fmt"
)
// 标签和json字段一一对应
type IT struct {
Company string `json:"company"`
Subjects []string`json:"subjects"`
IsOk bool `json:"isok"`
Price float64 `json:"price"`
}
func main() {
// 原始JSON字符串
jsonBuf := `{
"company": "itcast",
"subjects": ["GO","C++","Python","Test"],
"isok":true,
"price": 666.666
}`
var tmp IT
// 第二个参数必须传 &tmp 地址
err := json.Unmarshal([]byte(jsonBuf), &tmp)
if err != nil {
fmt.Println("反序列化失败 err = ", err)
return
}
fmt.Printf("解析结构体完整数据:%+v\n", tmp)
fmt.Println("公司名称:", tmp.Company)
}
5.2 JSON 解析到 map(动态未知 JSON 结构)
解析后 map 中 value 类型统一为 interface{},必须通过类型断言才能正常取值
go
Go
package main
import (
"encoding/json"
"fmt"
)
func main() {
jsonBuf := `{
"company": "itcast",
"subjects": ["GO","C++","Python","Test"],
"isok":true,
"price": 666.666
}`
// 定义map接收json
m := make(map[string]interface{}, 4)
err := json.Unmarshal([]byte(jsonBuf), &m)
if err != nil {
fmt.Println("反序列化失败 err = ", err)
return
}
fmt.Printf("原始map数据:%+v\n", m)
// 直接取值会报错,需要类型断言
// str := m["company"] 错误写法
// 方式1:简单断言单个字段
if companyStr, ok := m["company"].(string); ok {
fmt.Println("company =", companyStr)
}
// 方式2:switch type 批量类型判断(通用推荐)
for key, value := range m {
fmt.Printf("键:%s,原始值:%v\n", key, value)
switch data := value.(type) {
case string:
fmt.Printf("【%s】类型:string,值:%s\n", key, data)
case bool:
fmt.Printf("【%s】类型:bool,值:%v\n", key, data)
case float64:
fmt.Printf("【%s】类型:float64,值:%f\n", key, data)
case []interface{}:
fmt.Printf("【%s】类型:数组[]interface{},值:%v\n", key, data)
default:
fmt.Printf("【%s】未知类型\n", key)
}
}
}
六、高频易错点汇总(面试 / 开发踩坑清单)
- 结构体字段小写:反射无法读取,序列化直接丢失字段
- 反序列化不传地址:
Unmarshal无法修改变量值,解析后数据为空 - map 解析 JSON 数值自动是 float64,不能直接转 int,必须断言后强转
json:",string"标签只作用序列化,反序列化带引号数字也能自动匹配数值类型json:"-"标签字段序列化忽略,反序列化也不会赋值- JSON 字符串必须使用反引号 `````,单引号不能包裹多行字符串(Go 语法限制)
七、两种方案使用场景对比
表格
| 方案 | 优点 | 缺点 | 使用场景 |
|---|---|---|---|
| struct 结构体 | 类型安全、代码易读、字段校验、IDE 提示 | 需提前定义结构,适配动态 JSON 麻烦 | 接口参数、固定格式返回数据 |
| mapstringinterface{} | 无需定义结构,适配任意 JSON | 无类型提示,频繁类型断言,代码臃肿 | 未知第三方 JSON、动态配置数据 |
八、全文总结
- 序列化(Go → JSON):
json.Marshal(),支持 struct /map - 反序列化(JSON → Go):
json.Unmarshal(),支持 struct /map - struct tag 是自定义 JSON 输出的核心工具,掌握
-、自定义 key、,string三种常用写法 - map 解析 JSON 核心难点:
interface{}类型断言 - 业务开发优先使用结构体,动态不确定 JSON 再选用 map