encoding/json - JSON 编解码
概述
encoding/json 包提供了 JSON(JavaScript Object Notation)数据的编码和解码功能。
JSON 是什么:
- 📦 轻量级数据格式:基于 JavaScript 的对象表示法
- 🔧 通用数据交换:Web API、配置文件、数据存储的标准格式
- 📋 人类可读:文本格式,易于阅读和编写
- 🛠️ 跨语言支持:几乎所有编程语言都支持 JSON
主要用途:
- 🌐 Web API:RESTful API 的请求和响应数据
- 📧 配置文件:应用程序配置存储
- 🔐 数据传输:客户端与服务器之间的数据交换
- 📊 数据存储:NoSQL 数据库(如 MongoDB)的文档格式
- 🖼️ 序列化:对象的状态持久化
- 🔑 日志记录:结构化日志输出
重要说明:
- ⚠️ UTF-8 编码:JSON 默认使用 UTF-8 字符编码
- ⚠️ 字段可见性:只导出大写字段(导出字段)
- ⚠️ 标签语法:使用 struct tag 自定义字段名和选项
- ⚠️ 类型映射:Go 类型与 JSON 类型的映射关系
- ✅ 标准库支持:Go 标准库提供完整支持
- ✅ 流式处理:支持 Encoder/Decoder 流式编解码
- ✅ 自定义编解码:实现 Marshaler/Unmarshaler 接口
JSON 示例:
{
"name": "John Doe",
"age": 30,
"email": "john@example.com",
"active": true,
"tags": ["developer", "golang"],
"address": {
"city": "New York",
"zip": "10001"
}
}
JSON 基础
JSON 数据类型
6 种基本类型:
- 对象(Object):
{}- 键值对集合 - 数组(Array):
[]- 有序值列表 - 字符串(String):
""- 双引号包围的文本 - 数字(Number):整数或浮点数
- 布尔值(Boolean):
true或false - 空值(Null):
null
示例:
{
"string": "hello",
"number": 42,
"float": 3.14,
"boolean": true,
"null": null,
"array": [1, 2, 3],
"object": {"key": "value"}
}
Go 与 JSON 类型映射
| Go 类型 | JSON 类型 | 说明 |
|---|---|---|
| bool | boolean | true/false |
| int, int8-64 | number | 整数 |
| uint, uint8-64 | number | 无符号整数 |
| float32, float64 | number | 浮点数 |
| string | string | 字符串 |
| []T | array | 切片 |
| [N]T | array | 数组 |
| struct | object | 结构体 |
| map[string]T | object | 映射 |
| pointer | object/array/etc | 指针(解引用) |
| interface{} | any | 任意类型 |
| nil | null | 空值 |
| time.Time | string | ISO 8601 格式 |
| []byte | string | Base64 编码 |
核心函数
1. Marshal - 编码为 JSON
func Marshal(v interface{}) ([]byte, error)
功能:将 Go 值编码为 JSON 字节切片。
编码规则:
- 结构体字段必须大写(导出)
- 默认使用字段名作为 JSON 键
- 可使用 struct tag 自定义
- 忽略值为零值的字段(使用
omitempty) - 指针会被解引用
- nil 指针或接口编码为
null
示例:
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
user := User{Name: "John", Age: 30}
data, err := json.Marshal(user)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(data))
// 输出:{"name":"John","age":30}
2. MarshalIndent - 格式化编码
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
功能:将 Go 值编码为格式化的 JSON(带缩进)。
参数:
v:要编码的值prefix:每行前缀(通常为空字符串)indent:缩进字符串(通常为空格或制表符)
示例:
data, err := json.MarshalIndent(user, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(data))
/*
输出:
{
"name": "John",
"age": 30
}
*/
3. Unmarshal - 从 JSON 解码
func Unmarshal(data []byte, v interface{}) error
功能:将 JSON 数据解码到 Go 值。
参数:
data:JSON 字节切片v:指向目标变量的指针
解码规则:
- JSON 对象解码到结构体或 map
- JSON 数组解码到切片或数组
- JSON 数字默认解码为
float64 - 字段名匹配不区分大小写
- 未匹配的 JSON 字段被忽略
- 未初始化的 Go 字段保持零值
示例:
var user User
err := json.Unmarshal(data, &user)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", user)
4. Valid - 验证 JSON
func Valid(data []byte) bool
功能:检查 JSON 数据是否有效。
示例:
if json.Valid(data) {
fmt.Println("有效的 JSON")
} else {
fmt.Println("无效的 JSON")
}
5. HTMLEscape - HTML 转义
func HTMLEscape(dst *bytes.Buffer, src []byte)
功能:将 JSON 中的 HTML 特殊字符转义。
转义字符:
&→\u0026<→\u003c>→\u003e
示例:
data := []byte(`{"html": "<script>alert(1)</script>"}`)
var buf bytes.Buffer
json.HTMLEscape(&buf, data)
fmt.Println(buf.String())
// 输出:{"html": "\u003cscript\u003ealert(1)\u003c/script\u003e"}
核心类型
1. Encoder - JSON 编码器
type Encoder struct {
// 包含过滤或未导出的字段
}
功能:将 Go 值流式编码到 io.Writer。
创建方法:
func NewEncoder(w io.Writer) *Encoder
主要方法:
// 编码单个值
func (enc *Encoder) Encode(v interface{}) error
// 设置缩进
func (enc *Encoder) SetIndent(prefix, indent string)
// 设置 HTML 转义
func (enc *Encoder) SetEscapeHTML(on bool)
使用示例:
encoder := json.NewEncoder(os.Stdout)
err := encoder.Encode(user)
if err != nil {
log.Fatal(err)
}
2. Decoder - JSON 解码器
type Decoder struct {
// 包含过滤或未导出的字段
}
功能:从 io.Reader 流式解码 JSON。
创建方法:
func NewDecoder(r io.Reader) *Decoder
主要方法:
// 解码单个值
func (dec *Decoder) Decode(v interface{}) error
// 获取解码器中的下一个 token
func (dec *Decoder) Token() (Token, error)
// 检查是否还有更多数据
func (dec *Decoder) More() bool
// 返回解码器中的下一个 JSON 值
func (dec *Decoder) InputOffset() int64
// 使用指定类型存储下一个 JSON 值
func (dec *Decoder) UseNumber()
使用示例:
decoder := json.NewDecoder(reader)
var user User
err := decoder.Decode(&user)
if err != nil {
log.Fatal(err)
}
3. RawMessage - 原始 JSON
type RawMessage []byte
功能:存储原始 JSON 数据,延迟解码。
用途:
- 延迟解码(先存储,后解码)
- 解码未知结构的数据
- 部分解码(部分字段延迟处理)
示例:
type Event struct {
Type string `json:"type"`
Payload json.RawMessage `json:"payload"`
}
var event Event
json.Unmarshal(data, &event)
// 根据类型解码 payload
var payload map[string]interface{}
json.Unmarshal(event.Payload, &payload)
4. Number - JSON 数字
type Number string
功能:表示 JSON 数字,保持精度。
用途:
- 避免浮点数精度丢失
- 处理大整数(超过 int64 范围)
- 保持原始数字格式
方法:
// 转换为 float64
func (n Number) Float64() (float64, error)
// 转换为 int64
func (n Number) Int64() (int64, error)
// 转换为 string
func (n Number) String() string
使用示例:
// 使用 UseNumber() 保持精度
decoder := json.NewDecoder(reader)
decoder.UseNumber()
var data map[string]interface{}
decoder.Decode(&data)
num := data["large_number"].(json.Number)
intVal, _ := num.Int64()
5. Token - JSON Token
type Token interface{}
功能:表示 JSON 对象或数组的边界标记。
特殊值:
Delim('{'):对象开始Delim('}'):对象结束Delim('['):数组开始Delim(']'):数组结束
示例:
decoder := json.NewDecoder(reader)
for {
token, err := decoder.Token()
if err == io.EOF {
break
}
fmt.Printf("Token: %v\n", token)
}
Struct Tag 详解
基本语法
type Struct struct {
Field Type `json:"key,options"`
}
常用选项
| 选项 | 说明 | 示例 |
|---|---|---|
| 字段名 | 自定义 JSON 键名 | json:"name" |
| omitempty | 零值时忽略 | json:"name,omitempty" |
| string | 数字编码为字符串 | json:"age,string" |
| -“ | 忽略字段 | json:"-" |
字段名自定义
type User struct {
Name string `json:"username"` // 自定义键名
Email string `json:"email_address"` // 下划线命名
Password string `json:"-"` // 忽略此字段
}
omitempty 选项
零值定义:
0(数字类型)""(空字符串)nil(指针、切片、映射、接口)false(布尔)- 空结构体
type Product struct {
ID int `json:"id"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Price float64 `json:"price,omitempty"`
Tags []string `json:"tags,omitempty"`
}
// 如果 Name 为空字符串,则不会出现在 JSON 中
string 选项
用途:将数字编码为字符串(或从字符串解码数字)。
type Config struct {
Port int `json:"port,string"` // "8080" ↔ 8080
Timeout int64 `json:"timeout,string"` // "30" ↔ 30
Enabled bool `json:"enabled,string"` // "true" ↔ true
}
组合选项
type Data struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Count int `json:"count,string,omitempty"`
}
完整示例
示例 1:基本编解码
package main
import (
"encoding/json"
"fmt"
"log"
)
// User 用户结构
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}
func main() {
fmt.Println("=== JSON 基本编解码 ===\n")
// 1. 创建数据
user := User{
ID: 1,
Name: "John Doe",
Email: "john@example.com",
Age: 30,
}
fmt.Printf("原始数据:\n")
fmt.Printf(" ID: %d\n", user.ID)
fmt.Printf(" Name: %s\n", user.Name)
fmt.Printf(" Email: %s\n", user.Email)
fmt.Printf(" Age: %d\n\n", user.Age)
// 2. 编码为 JSON
fmt.Println("2. 编码为 JSON:")
data, err := json.Marshal(user)
if err != nil {
log.Fatal(err)
}
fmt.Printf(" 紧凑格式:%s\n", string(data))
// 格式化输出
indentData, err := json.MarshalIndent(user, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Printf("\n 格式化格式:\n%s\n\n", string(indentData))
// 3. 从 JSON 解码
fmt.Println("3. 从 JSON 解码:")
var decoded User
err = json.Unmarshal(data, &decoded)
if err != nil {
log.Fatal(err)
}
fmt.Printf(" 解码结果:\n")
fmt.Printf(" ID: %d\n", decoded.ID)
fmt.Printf(" Name: %s\n", decoded.Name)
fmt.Printf(" Email: %s\n", decoded.Email)
fmt.Printf(" Age: %d\n\n", decoded.Age)
// 4. 验证
fmt.Printf("验证:%v\n", user == decoded)
// 5. 验证 JSON 有效性
fmt.Printf("JSON 有效性:%v\n", json.Valid(data))
}
输出:
=== JSON 基本编解码 ===
原始数据:
ID: 1
Name: John Doe
Email: john@example.com
Age: 30
2. 编码为 JSON:
紧凑格式:{"id":1,"name":"John Doe","email":"john@example.com","age":30}
格式化格式:
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"age": 30
}
3. 从 JSON 解码:
解码结果:
ID: 1
Name: John Doe
Email: john@example.com
Age: 30
验证:true
JSON 有效性:true
示例 2:Struct Tag 使用
package main
import (
"encoding/json"
"fmt"
"log"
)
// Product 产品(使用各种 struct tag)
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Price float64 `json:"price"`
Category string `json:"category,omitempty"`
Tags []string `json:"tags,omitempty"`
InternalID int `json:"-"` // 完全忽略
secret string // 未导出,自动忽略
}
// Config 配置(使用 string 选项)
type Config struct {
Port int `json:"port,string"`
Host string `json:"host"`
Timeout int64 `json:"timeout,string"`
Debug bool `json:"debug,string"`
}
func main() {
fmt.Println("=== Struct Tag 使用 ===\n")
// 1. omitempty 测试
fmt.Println("1. omitempty 测试:")
product1 := Product{
ID: 1,
Name: "Laptop",
Description: "High performance laptop",
Price: 999.99,
Category: "Electronics",
Tags: []string{"computer", "portable"},
InternalID: 12345,
secret: "secret",
}
data1, _ := json.MarshalIndent(product1, "", " ")
fmt.Printf("完整产品:\n%s\n\n", string(data1))
// 空字段测试
product2 := Product{
ID: 2,
Name: "Mouse",
Price: 29.99,
// Description, Category, Tags 为空
}
data2, _ := json.MarshalIndent(product2, "", " ")
fmt.Printf("省略空字段:\n%s\n\n", string(data2))
// 2. string 选项测试
fmt.Println("2. string 选项测试:")
config := Config{
Port: 8080,
Host: "localhost",
Timeout: 30,
Debug: true,
}
data3, err := json.MarshalIndent(config, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Printf("编码配置:\n%s\n\n", string(data3))
// 3. 解码 string 选项
fmt.Println("3. 解码 string 选项:")
jsonStr := `{
"port": "9090",
"host": "example.com",
"timeout": "60",
"debug": "false"
}`
var decodedConfig Config
err = json.Unmarshal([]byte(jsonStr), &decodedConfig)
if err != nil {
log.Fatal(err)
}
fmt.Printf("解码配置:\n")
fmt.Printf(" Port: %d (类型:%T)\n", decodedConfig.Port, decodedConfig.Port)
fmt.Printf(" Host: %s\n", decodedConfig.Host)
fmt.Printf(" Timeout: %d\n", decodedConfig.Timeout)
fmt.Printf(" Debug: %v\n\n", decodedConfig.Debug)
// 4. 字段名映射
fmt.Println("4. 字段名映射:")
jsonCustom := `{
"id": 3,
"name": "Keyboard",
"description": "Mechanical keyboard",
"price": 79.99,
"category": "Peripherals",
"tags": ["input", "gaming"]
}`
var product3 Product
err = json.Unmarshal([]byte(jsonCustom), &product3)
if err != nil {
log.Fatal(err)
}
fmt.Printf("解码产品:\n")
fmt.Printf(" ID: %d\n", product3.ID)
fmt.Printf(" Name: %s\n", product3.Name)
fmt.Printf(" Description: %s\n", product3.Description)
fmt.Printf(" Price: %.2f\n", product3.Price)
fmt.Printf(" Category: %s\n", product3.Category)
fmt.Printf(" Tags: %v\n", product3.Tags)
fmt.Printf(" InternalID: %d (未出现在 JSON 中)\n", product3.InternalID)
}
输出:
=== Struct Tag 使用 ===
1. omitempty 测试:
完整产品:
{
"id": 1,
"name": "Laptop",
"description": "High performance laptop",
"price": 999.99,
"category": "Electronics",
"tags": [
"computer",
"portable"
]
}
省略空字段:
{
"id": 2,
"name": "Mouse",
"price": 29.99
}
2. string 选项测试:
编码配置:
{
"port": "8080",
"host": "localhost",
"timeout": "30",
"debug": "true"
}
3. 解码 string 选项:
解码配置:
Port: 9090 (类型:int)
Host: example.com
Timeout: 60
Debug: false
4. 字段名映射:
解码产品:
ID: 3
Name: Keyboard
Description: Mechanical keyboard
Price: 79.99
Category: Peripherals
Tags: [input gaming]
InternalID: 12345 (未出现在 JSON 中)
示例 3:复杂数据结构
package main
import (
"encoding/json"
"fmt"
"log"
"time"
)
// Address 地址
type Address struct {
Street string `json:"street"`
City string `json:"city"`
State string `json:"state"`
ZipCode string `json:"zip_code"`
Country string `json:"country"`
}
// Contact 联系方式
type Contact struct {
Type string `json:"type"`
Value string `json:"value"`
}
// User 用户(嵌套结构)
type User struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
Address Address `json:"address"`
Contacts []Contact `json:"contacts"`
Metadata map[string]interface{} `json:"metadata"`
}
// Company 公司
type Company struct {
Name string `json:"name"`
Founded int `json:"founded"`
Employees int `json:"employees"`
Departments []string `json:"departments"`
CEO *User `json:"ceo"` // 指针
Offices []Address `json:"offices"`
}
func main() {
fmt.Println("=== 复杂数据结构 ===\n")
// 1. 创建嵌套数据
user := User{
ID: 1,
Username: "john_doe",
Email: "john@example.com",
CreatedAt: time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC),
Address: Address{
Street: "123 Main St",
City: "New York",
State: "NY",
ZipCode: "10001",
Country: "USA",
},
Contacts: []Contact{
{Type: "phone", Value: "+1-555-1234"},
{Type: "email", Value: "john.doe@example.com"},
},
Metadata: map[string]interface{}{
"age": 30,
"married": true,
"hobbies": []string{"reading", "coding"},
},
}
// 2. 编码
fmt.Println("2. 编码嵌套结构:")
data, err := json.MarshalIndent(user, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n\n", string(data))
// 3. 解码
fmt.Println("3. 解码嵌套结构:")
var decoded User
err = json.Unmarshal(data, &decoded)
if err != nil {
log.Fatal(err)
}
fmt.Printf("解码用户:\n")
fmt.Printf(" 用户名:%s\n", decoded.Username)
fmt.Printf(" 城市:%s\n", decoded.Address.City)
fmt.Printf(" 联系方式:%d 个\n", len(decoded.Contacts))
fmt.Printf(" 元数据年龄:%v\n", decoded.Metadata["age"])
// 4. 公司结构(包含指针)
fmt.Println("\n4. 公司结构:")
company := Company{
Name: "TechCorp",
Founded: 2010,
Employees: 500,
Departments: []string{"Engineering", "Sales", "Marketing"},
CEO: &user, // 指向之前的 user
Offices: []Address{
{Street: "1 Tech Plaza", City: "San Francisco", State: "CA", ZipCode: "94105", Country: "USA"},
{Street: "2 Innovation Way", City: "New York", State: "NY", ZipCode: "10001", Country: "USA"},
},
}
companyData, _ := json.MarshalIndent(company, "", " ")
fmt.Printf("%s\n\n", string(companyData))
// 5. 解码公司
var decodedCompany Company
err = json.Unmarshal(companyData, &decodedCompany)
if err != nil {
log.Fatal(err)
}
fmt.Printf("解码公司:\n")
fmt.Printf(" 名称:%s\n", decodedCompany.Name)
fmt.Printf(" 成立年份:%d\n", decodedCompany.Founded)
fmt.Printf(" 员工数:%d\n", decodedCompany.Employees)
fmt.Printf(" 部门数:%d\n", len(decodedCompany.Departments))
if decodedCompany.CEO != nil {
fmt.Printf(" CEO: %s\n", decodedCompany.CEO.Username)
}
fmt.Printf(" 办公室:%d 个\n", len(decodedCompany.Offices))
// 6. 访问 map 数据
fmt.Println("\n6. 访问 Map 数据:")
if meta, ok := decoded.Metadata["hobbies"].([]interface{}); ok {
fmt.Printf("爱好:")
for _, hobby := range meta {
fmt.Printf("%s ", hobby.(string))
}
fmt.Println()
}
}
输出:
=== 复杂数据结构 ===
2. 编码嵌套结构:
{
"id": 1,
"username": "john_doe",
"email": "john@example.com",
"created_at": "2024-01-15T10:30:00Z",
"address": {
"street": "123 Main St",
"city": "New York",
"state": "NY",
"zip_code": "10001",
"country": "USA"
},
"contacts": [
{
"type": "phone",
"value": "+1-555-1234"
},
{
"type": "email",
"value": "john.doe@example.com"
}
],
"metadata": {
"age": 30,
"hobbies": [
"reading",
"coding"
],
"married": true
}
}
3. 解码嵌套结构:
解码用户:
用户名:john_doe
城市:New York
联系方式:2 个
元数据年龄:30
4. 公司结构:
{
"name": "TechCorp",
"founded": 2010,
"employees": 500,
"departments": [
"Engineering",
"Sales",
"Marketing"
],
"ceo": {
"id": 1,
"username": "john_doe",
...
},
"offices": [
{
"street": "1 Tech Plaza",
"city": "San Francisco",
...
},
...
]
}
解码公司:
名称:TechCorp
成立年份:2010
员工数:500
部门数:3
CEO: john_doe
办公室:2 个
6. 访问 Map 数据:
爱好:reading coding
示例 4:流式编解码
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"os"
"strings"
)
// Message 消息
type Message struct {
ID int `json:"id"`
Content string `json:"content"`
Type string `json:"type"`
}
func main() {
fmt.Println("=== 流式编解码 ===\n")
// 1. 流式编码
fmt.Println("1. 流式编码:")
messages := []Message{
{ID: 1, Content: "Hello", Type: "text"},
{ID: 2, Content: "World", Type: "text"},
{ID: 3, Content: "Test", Type: "data"},
}
var buf strings.Builder
encoder := json.NewEncoder(&buf)
// 编码多个值
for _, msg := range messages {
err := encoder.Encode(msg)
if err != nil {
log.Fatal(err)
}
}
fmt.Printf("编码结果:\n%s", buf.String())
// 2. 流式解码
fmt.Println("2. 流式解码:")
decoder := json.NewDecoder(strings.NewReader(buf.String()))
for {
var msg Message
err := decoder.Decode(&msg)
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
fmt.Printf(" 消息 %d: [%s] %s\n", msg.ID, msg.Type, msg.Content)
}
// 3. 使用 More() 检查
fmt.Println("\n3. 使用 More() 检查:")
jsonArray := `[{"id":1},{"id":2},{"id":3}]`
decoder = json.NewDecoder(strings.NewReader(jsonArray))
// 读取数组开始
decoder.Token()
count := 0
for decoder.More() {
var m map[string]interface{}
decoder.Decode(&m)
count++
}
// 读取数组结束
decoder.Token()
fmt.Printf(" 解码了 %d 个对象\n\n", count)
// 4. 使用 Token() 解析
fmt.Println("4. 使用 Token() 解析:")
complexJSON := `{
"users": [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
],
"count": 2
}`
decoder = json.NewDecoder(strings.NewReader(complexJSON))
for {
token, err := decoder.Token()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
fmt.Printf(" Token: %v (类型:%T)\n", token, token)
}
// 5. 文件流式处理
fmt.Println("\n5. 文件流式处理:")
// 写入文件
file, err := os.Create("messages.jsonl")
if err != nil {
log.Fatal(err)
}
defer file.Close()
encoder = json.NewEncoder(file)
for i := 1; i <= 5; i++ {
encoder.Encode(Message{ID: i, Content: fmt.Sprintf("Message %d", i), Type: "info"})
}
fmt.Printf(" ✓ 已写入 messages.jsonl\n")
// 读取文件
file2, err := os.Open("messages.jsonl")
if err != nil {
log.Fatal(err)
}
defer file2.Close()
decoder = json.NewDecoder(file2)
fmt.Println(" 读取消息:")
for {
var msg Message
err := decoder.Decode(&msg)
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
fmt.Printf(" [%d] %s\n", msg.ID, msg.Content)
}
// 清理
os.Remove("messages.jsonl")
}
输出:
=== 流式编解码 ===
1. 流式编码:
编码结果:
{"id":1,"content":"Hello","type":"text"}
{"id":2,"content":"World","type":"text"}
{"id":3,"content":"Test","type":"data"}
2. 流式解码:
消息 1: [text] Hello
消息 2: [text] World
消息 3: [data] Test
3. 使用 More() 检查:
解码了 3 个对象
4. 使用 Token() 解析:
Token: { (类型:json.Delim)
Token: users (类型:string)
Token: [ (类型:json.Delim)
Token: { (类型:json.Delim)
Token: name (类型:string)
Token: Alice (类型:string)
Token: age (类型:string)
Token: 30 (类型:float64)
Token: } (类型:json.Delim)
Token: { (类型:json.Delim)
Token: name (类型:string)
Token: Bob (类型:string)
Token: age (类型:string)
Token: 25 (类型:float64)
Token: } (类型:json.Delim)
Token: ] (类型:json.Delim)
Token: count (类型:string)
Token: 2 (类型:float64)
Token: } (类型:json.Delim)
5. 文件流式处理:
✓ 已写入 messages.jsonl
读取消息:
[1] Message 1
[2] Message 2
[3] Message 3
[4] Message 4
[5] Message 5
示例 5:接口和自定义类型
package main
import (
"encoding/json"
"fmt"
"log"
"strconv"
)
// Shape 形状接口
type Shape interface {
Area() float64
}
// Circle 圆形
type Circle struct {
Type string `json:"type"`
Radius float64 `json:"radius"`
}
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
// Rectangle 矩形
type Rectangle struct {
Type string `json:"type"`
Width float64 `json:"width"`
Height float64 `json:"height"`
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// CustomInt 自定义整数类型
type CustomInt int
// MarshalJSON 自定义编码
func (c CustomInt) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%d\"", c)), nil
}
// UnmarshalJSON 自定义解码
func (c *CustomInt) UnmarshalJSON(data []byte) error {
// 移除引号
s := string(data)
if len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' {
s = s[1 : len(s)-1]
}
val, err := strconv.Atoi(s)
if err != nil {
return err
}
*c = CustomInt(val)
return nil
}
// Data 包含自定义类型
type Data struct {
ID CustomInt `json:"id"`
Name string `json:"name"`
Value int `json:"value"`
}
func main() {
fmt.Println("=== 接口和自定义类型 ===\n")
// 1. 接口类型编码
fmt.Println("1. 接口类型编码:")
shapes := []Shape{
Circle{Type: "circle", Radius: 5.0},
Rectangle{Type: "rectangle", Width: 4.0, Height: 6.0},
Circle{Type: "circle", Radius: 3.0},
}
// 直接编码接口会丢失类型信息
// 需要手动处理
type ShapeWrapper struct {
Type string `json:"type"`
Radius float64 `json:"radius,omitempty"`
Width float64 `json:"width,omitempty"`
Height float64 `json:"height,omitempty"`
}
for _, shape := range shapes {
var wrapper ShapeWrapper
switch s := shape.(type) {
case Circle:
wrapper = ShapeWrapper{Type: "circle", Radius: s.Radius}
case Rectangle:
wrapper = ShapeWrapper{Type: "rectangle", Width: s.Width, Height: s.Height}
}
data, _ := json.Marshal(wrapper)
fmt.Printf(" %s\n", string(data))
}
// 2. 接口类型解码
fmt.Println("\n2. 接口类型解码:")
jsonShapes := []string{
`{"type":"circle","radius":5.0}`,
`{"type":"rectangle","width":4.0,"height":6.0}`,
}
for _, jsonStr := range jsonShapes {
var wrapper ShapeWrapper
json.Unmarshal([]byte(jsonStr), &wrapper)
var shape Shape
switch wrapper.Type {
case "circle":
shape = Circle{Type: wrapper.Type, Radius: wrapper.Radius}
case "rectangle":
shape = Rectangle{Type: wrapper.Type, Width: wrapper.Width, Height: wrapper.Height}
}
fmt.Printf(" 类型:%s, 面积:%.2f\n", wrapper.Type, shape.Area())
}
// 3. 自定义类型编码
fmt.Println("\n3. 自定义类型编解码:")
data := Data{
ID: 123,
Name: "Test",
Value: 456,
}
jsonData, err := json.MarshalIndent(data, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Printf("编码:\n%s\n\n", string(jsonData))
// 4. 自定义类型解码
fmt.Println("4. 自定义类型解码:")
jsonInput := `{
"id": "789",
"name": "Custom",
"value": 999
}`
var decoded Data
err = json.Unmarshal([]byte(jsonInput), &decoded)
if err != nil {
log.Fatal(err)
}
fmt.Printf("解码:\n")
fmt.Printf(" ID: %d (类型:%T)\n", decoded.ID, decoded.ID)
fmt.Printf(" Name: %s\n", decoded.Name)
fmt.Printf(" Value: %d\n\n", decoded.Value)
// 5. RawMessage 延迟解码
fmt.Println("5. RawMessage 延迟解码:")
type Event struct {
Type string `json:"type"`
Payload json.RawMessage `json:"payload"`
}
eventJSON := `{
"type": "user_created",
"payload": {"id": 1, "name": "Alice", "email": "alice@example.com"}
}`
var event Event
json.Unmarshal([]byte(eventJSON), &event)
fmt.Printf("事件类型:%s\n", event.Type)
fmt.Printf("原始 Payload: %s\n", string(event.Payload))
// 延迟解码 Payload
var payload map[string]interface{}
json.Unmarshal(event.Payload, &payload)
fmt.Printf("解码 Payload:\n")
fmt.Printf(" ID: %v\n", payload["id"])
fmt.Printf(" Name: %v\n", payload["name"])
fmt.Printf(" Email: %v\n", payload["email"])
}
输出:
=== 接口和自定义类型 ===
1. 接口类型编码:
{"type":"circle","radius":5}
{"type":"rectangle","width":4,"height":6}
{"type":"circle","radius":3}
2. 接口类型解码:
类型:circle, 面积:78.54
类型:rectangle, 面积:24.00
3. 自定义类型编解码:
编码:
{
"id": "123",
"name": "Test",
"value": 456
}
4. 自定义类型解码:
解码:
ID: 789 (类型:main.CustomInt)
Name: Custom
Value: 999
5. RawMessage 延迟解码:
事件类型:user_created
原始 Payload: {"id": 1, "name": "Alice", "email": "alice@example.com"}
解码 Payload:
ID: 1
Name: Alice
Email: alice@example.com
示例 6:错误处理
package main
import (
"encoding/json"
"fmt"
"log"
)
// User 用户
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}
func main() {
fmt.Println("=== JSON 错误处理 ===\n")
// 1. 无效 JSON 语法
fmt.Println("1. 无效 JSON 语法:")
invalidJSONs := []string{
`{"name": "John",}`, // 尾随逗号
`{"name": "John"}`, // 缺少右括号
`{"name": 'John'}`, // 单引号
`{name: "John"}`, // 未加引号的键
`{"name": "John"`, // 缺少右大括号
}
for i, jsonStr := range invalidJSONs {
var user User
err := json.Unmarshal([]byte(jsonStr), &user)
fmt.Printf(" 测试 %d: %s\n", i+1, jsonStr)
if err != nil {
fmt.Printf(" ✗ 错误:%v\n\n", err)
} else {
fmt.Printf(" ✓ 成功(意外)\n\n")
}
}
// 2. 类型不匹配
fmt.Println("2. 类型不匹配:")
typeMismatchCases := []struct {
json string
description string
}{
{`{"id": "not_a_number", "name": "John", "email": "john@example.com", "age": 30}`, "ID 应为整数"},
{`{"id": 1, "name": 123, "email": "john@example.com", "age": 30}`, "Name 应为字符串"},
{`{"id": 1, "name": "John", "email": "john@example.com", "age": "thirty"}`, "Age 应为整数"},
}
for _, tc := range typeMismatchCases {
var user User
err := json.Unmarshal([]byte(tc.json), &user)
fmt.Printf(" %s:\n", tc.description)
fmt.Printf(" JSON: %s\n", tc.json)
if err != nil {
fmt.Printf(" ✗ 错误:%v\n\n", err)
} else {
fmt.Printf(" ✓ 成功(Go 会尝试转换)\n\n")
}
}
// 3. 字段缺失和多余
fmt.Println("3. 字段缺失和多余:")
// 字段缺失(不会报错)
missingField := `{"id": 1, "name": "John"}`
var user1 User
err := json.Unmarshal([]byte(missingField), &user1)
fmt.Printf(" 字段缺失:\n")
fmt.Printf(" JSON: %s\n", missingField)
if err != nil {
fmt.Printf(" ✗ 错误:%v\n", err)
} else {
fmt.Printf(" ✓ 成功(缺失字段为零值)\n")
fmt.Printf(" 结果:%+v\n\n", user1)
}
// 字段多余(不会报错)
extraField := `{"id": 1, "name": "John", "email": "john@example.com", "age": 30, "extra": "ignored"}`
var user2 User
err = json.Unmarshal([]byte(extraField), &user2)
fmt.Printf(" 字段多余:\n")
fmt.Printf(" JSON: %s\n", extraField)
if err != nil {
fmt.Printf(" ✗ 错误:%v\n", err)
} else {
fmt.Printf(" ✓ 成功(多余字段被忽略)\n")
fmt.Printf(" 结果:%+v\n\n", user2)
}
// 4. 空值和零值
fmt.Println("4. 空值和零值:")
nullJSON := `{"id": null, "name": null, "email": null, "age": null}`
var user3 User
err = json.Unmarshal([]byte(nullJSON), &user3)
fmt.Printf(" null 值:\n")
fmt.Printf(" JSON: %s\n", nullJSON)
if err != nil {
fmt.Printf(" ✗ 错误:%v\n", err)
} else {
fmt.Printf(" ✓ 成功(null 转换为零值)\n")
fmt.Printf(" 结果:%+v\n\n", user3)
}
// 5. 数组与切片不匹配
fmt.Println("5. 数组与切片不匹配:")
type Data struct {
Array [3]int `json:"array"`
Slice []int `json:"slice"`
}
arrayMismatch := `{"array": [1, 2, 3, 4, 5], "slice": [1, 2, 3]}`
var data Data
err = json.Unmarshal([]byte(arrayMismatch), &data)
fmt.Printf(" 数组长度不匹配:\n")
fmt.Printf(" JSON: %s\n", arrayMismatch)
if err != nil {
fmt.Printf(" ✗ 错误:%v\n", err)
} else {
fmt.Printf(" ✓ 成功(超出部分被忽略)\n")
fmt.Printf(" 结果:Array=%v, Slice=%v\n\n", data.Array, data.Slice)
}
// 6. 验证 JSON
fmt.Println("6. 验证 JSON:")
testCases := []struct {
json string
valid bool
}{
{`{"valid": true}`, true},
{`[1, 2, 3]`, true},
{`"string"`, true},
{`123`, true},
{`true`, true},
{`null`, true},
{`{invalid}`, false},
{`[unclosed`, false},
{``, false},
}
for _, tc := range testCases {
isValid := json.Valid([]byte(tc.json))
status := "✓"
if isValid != tc.valid {
status = "✗"
}
fmt.Printf(" %s %s (预期:%v, 实际:%v)\n", status, tc.json, tc.valid, isValid)
}
// 7. Decoder 错误
fmt.Println("\n7. Decoder 错误:")
decoder := json.NewDecoder(strings.NewReader(`{invalid}`))
var result interface{}
err = decoder.Decode(&result)
if err != nil {
fmt.Printf(" ✓ 捕获错误:%v\n", err)
}
}
输出:
=== JSON 错误处理 ===
1. 无效 JSON 语法:
测试 1: {"name": "John",}
✗ 错误:invalid character '}' looking for beginning of object key string
测试 2: {"name": "John"}
✓ 成功(意外)
测试 3: {"name": 'John'}
✗ 错误:invalid character '\'' looking for beginning of object key string
测试 4: {name: "John"}
✗ 错误:invalid character 'n' looking for beginning of object key string
测试 5: {"name": "John"
✗ 错误:unexpected end of JSON input
2. 类型不匹配:
ID 应为整数:
JSON: {"id": "not_a_number", "name": "John", "email": "john@example.com", "age": 30}
✗ 错误:json: cannot unmarshal string into Go struct field User.id of type int
Name 应为字符串:
JSON: {"id": 1, "name": 123, "email": "john@example.com", "age": 30}
✗ 错误:json: cannot unmarshal number into Go struct field User.name of type string
Age 应为整数:
JSON: {"id": 1, "name": "John", "email": "john@example.com", "age": "thirty"}
✗ 错误:json: cannot unmarshal string into Go struct field User.age of type int
3. 字段缺失和多余:
字段缺失:
JSON: {"id": 1, "name": "John"}
✓ 成功(缺失字段为零值)
结果:{ID:1 Name:John Email: Age:0}
字段多余:
JSON: {"id": 1, "name": "John", "email": "john@example.com", "age": 30, "extra": "ignored"}
✓ 成功(多余字段被忽略)
结果:{ID:1 Name:John Email:john@example.com Age:30}
4. 空值和零值:
null 值:
JSON: {"id": null, "name": null, "email": null, "age": null}
✓ 成功(null 转换为零值)
结果:{ID:0 Name: Email: Age:0}
5. 数组与切片不匹配:
数组长度不匹配:
JSON: {"array": [1, 2, 3, 4, 5], "slice": [1, 2, 3]}
✓ 成功(超出部分被忽略)
结果:Array=[1 2 3], Slice=[1 2 3]
6. 验证 JSON:
✓ {"valid": true} (预期:true, 实际:true)
✓ [1, 2, 3] (预期:true, 实际:true)
✓ "string" (预期:true, 实际:true)
✓ 123 (预期:true, 实际:true)
✓ true (预期:true, 实际:true)
✓ null (预期:true, 实际:true)
✓ {invalid} (预期:false, 实际:false)
✓ [unclosed (预期:false, 实际:false)
✓ (预期:false, 实际:false)
7. Decoder 错误:
✓ 捕获错误:invalid character 'i' looking for beginning of object key string
示例 7:Web API 应用
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"strings"
)
// User 用户
type User struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Age int `json:"age,omitempty"`
}
// Response API 响应
type Response struct {
Success bool `json:"success"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
Error string `json:"error,omitempty"`
}
// ErrorResponse 错误响应
type ErrorResponse struct {
Success bool `json:"success"`
Error string `json:"error"`
Code int `json:"code"`
}
// 模拟用户数据库
var users = map[int]User{
1: {ID: 1, Username: "alice", Email: "alice@example.com", Age: 30},
2: {ID: 2, Username: "bob", Email: "bob@example.com", Age: 25},
3: {ID: 3, Username: "charlie", Email: "charlie@example.com", Age: 35},
}
var nextID = 4
// WriteJSON 写入 JSON 响应
func WriteJSON(w http.ResponseWriter, status int, data interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}
// WriteError 写入错误响应
func WriteError(w http.ResponseWriter, status int, message string, code int) {
WriteJSON(w, status, ErrorResponse{
Success: false,
Error: message,
Code: code,
})
}
// GetUser 获取用户
func GetUser(w http.ResponseWriter, r *http.Request) {
// 从 URL 获取 ID
idStr := strings.TrimPrefix(r.URL.Path, "/users/")
if idStr == "" {
WriteError(w, http.StatusBadRequest, "Missing user ID", 4001)
return
}
// 解析 ID(简化示例)
var id int
fmt.Sscanf(idStr, "%d", &id)
user, exists := users[id]
if !exists {
WriteError(w, http.StatusNotFound, "User not found", 4002)
return
}
WriteJSON(w, http.StatusOK, Response{
Success: true,
Message: "User retrieved successfully",
Data: user,
})
}
// CreateUser 创建用户
func CreateUser(w http.ResponseWriter, r *http.Request) {
// 读取请求体
body, err := io.ReadAll(r.Body)
if err != nil {
WriteError(w, http.StatusBadRequest, "Invalid request body", 4003)
return
}
defer r.Body.Close()
// 解码 JSON
var input struct {
Username string `json:"username"`
Email string `json:"email"`
Age int `json:"age,omitempty"`
}
err = json.Unmarshal(body, &input)
if err != nil {
WriteError(w, http.StatusBadRequest, "Invalid JSON: "+err.Error(), 4004)
return
}
// 验证
if input.Username == "" || input.Email == "" {
WriteError(w, http.StatusBadRequest, "Username and email are required", 4005)
return
}
// 创建用户
user := User{
ID: nextID,
Username: input.Username,
Email: input.Email,
Age: input.Age,
}
nextID++
users[user.ID] = user
WriteJSON(w, http.StatusCreated, Response{
Success: true,
Message: "User created successfully",
Data: user,
})
}
// ListUsers 列出所有用户
func ListUsers(w http.ResponseWriter, r *http.Request) {
userList := make([]User, 0, len(users))
for _, user := range users {
userList = append(userList, user)
}
WriteJSON(w, http.StatusOK, Response{
Success: true,
Message: "Users retrieved successfully",
Data: userList,
})
}
// UserHandler 用户处理函数
func UserHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
if r.URL.Path == "/users" {
ListUsers(w, r)
} else {
GetUser(w, r)
}
case http.MethodPost:
CreateUser(w, r)
default:
WriteError(w, http.StatusMethodNotAllowed, "Method not allowed", 4006)
}
}
// main 示例(不实际运行服务器)
func main() {
fmt.Println("=== Web API 应用 ===\n")
// 模拟请求测试
fmt.Println("1. 获取用户列表:")
var listResp Response
jsonData := `{"success":true,"message":"Users retrieved successfully","data":[{"id":1,"username":"alice","email":"alice@example.com","age":30},{"id":2,"username":"bob","email":"bob@example.com","age":25}]}`
json.Unmarshal([]byte(jsonData), &listResp)
fmt.Printf(" 成功:%v\n", listResp.Success)
if users, ok := listResp.Data.([]interface{}); ok {
fmt.Printf(" 用户数:%d\n\n", len(users))
}
fmt.Println("2. 获取单个用户:")
var getResp Response
jsonData = `{"success":true,"message":"User retrieved successfully","data":{"id":1,"username":"alice","email":"alice@example.com","age":30}}`
json.Unmarshal([]byte(jsonData), &getResp)
fmt.Printf(" 成功:%v\n", getResp.Success)
fmt.Printf(" 消息:%s\n\n", getResp.Message)
fmt.Println("3. 创建用户响应:")
var createResp Response
jsonData = `{"success":true,"message":"User created successfully","data":{"id":4,"username":"david","email":"david@example.com"}}`
json.Unmarshal([]byte(jsonData), &createResp)
fmt.Printf(" 成功:%v\n", createResp.Success)
fmt.Printf(" 消息:%s\n\n", createResp.Message)
fmt.Println("4. 错误响应:")
var errorResp ErrorResponse
jsonData = `{"success":false,"error":"User not found","code":4002}``
json.Unmarshal([]byte(jsonData), &errorResp)
fmt.Printf(" 成功:%v\n", errorResp.Success)
fmt.Printf(" 错误:%s\n", errorResp.Error)
fmt.Printf(" 代码:%d\n\n", errorResp.Code)
fmt.Println("✓ Web API 示例完成")
fmt.Println("\n实际使用时,运行:")
fmt.Println(" http.HandleFunc(\"/users\", UserHandler)")
fmt.Println(" http.ListenAndServe(\":8080\", nil)")
}
输出:
=== Web API 应用 ===
1. 获取用户列表:
成功:true
用户数:2
2. 获取单个用户:
成功:true
消息:User retrieved successfully
3. 创建用户响应:
成功:true
消息:User created successfully
4. 错误响应:
成功:false
错误:User not found
代码:4002
✓ Web API 示例完成
实际使用时,运行:
http.HandleFunc("/users", UserHandler)
http.ListenAndServe(":8080", nil)
示例 8:配置文件处理
package main
import (
"encoding/json"
"fmt"
"log"
"os"
)
// Config 配置结构
type Config struct {
App AppConfig `json:"app"`
Database DatabaseConfig `json:"database"`
Server ServerConfig `json:"server"`
Features []string `json:"features"`
}
// AppConfig 应用配置
type AppConfig struct {
Name string `json:"name"`
Version string `json:"version"`
Debug bool `json:"debug"`
}
// DatabaseConfig 数据库配置
type DatabaseConfig struct {
Host string `json:"host"`
Port int `json:"port"`
User string `json:"user"`
Password string `json:"password"`
Database string `json:"database"`
SSL bool `json:"ssl"`
}
// ServerConfig 服务器配置
type ServerConfig struct {
Host string `json:"host"`
Port int `json:"port"`
ReadTimeout int `json:"read_timeout"`
WriteTimeout int `json:"write_timeout"`
AllowedOrigins []string `json:"allowed_origins"`
}
// LoadConfig 加载配置文件
func LoadConfig(filename string) (*Config, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
var config Config
decoder := json.NewDecoder(file)
err = decoder.Decode(&config)
if err != nil {
return nil, err
}
return &config, nil
}
// SaveConfig 保存配置文件
func SaveConfig(filename string, config *Config) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
return encoder.Encode(config)
}
// DefaultConfig 默认配置
func DefaultConfig() *Config {
return &Config{
App: AppConfig{
Name: "MyApp",
Version: "1.0.0",
Debug: false,
},
Database: DatabaseConfig{
Host: "localhost",
Port: 5432,
User: "admin",
Password: "secret",
Database: "mydb",
SSL: false,
},
Server: ServerConfig{
Host: "0.0.0.0",
Port: 8080,
ReadTimeout: 30,
WriteTimeout: 30,
AllowedOrigins: []string{"*"},
},
Features: []string{"feature1", "feature2"},
}
}
func main() {
fmt.Println("=== 配置文件处理 ===\n")
// 1. 创建默认配置
fmt.Println("1. 创建默认配置:")
config := DefaultConfig()
// 2. 保存配置
fmt.Println("2. 保存配置到 config.json:")
err := SaveConfig("config.json", config)
if err != nil {
log.Fatal(err)
}
fmt.Println(" ✓ 配置已保存\n")
// 3. 加载配置
fmt.Println("3. 从 config.json 加载配置:")
loadedConfig, err := LoadConfig("config.json")
if err != nil {
log.Fatal(err)
}
// 4. 显示配置
fmt.Printf(" 应用名称:%s\n", loadedConfig.App.Name)
fmt.Printf(" 版本:%s\n", loadedConfig.App.Version)
fmt.Printf(" 调试模式:%v\n", loadedConfig.App.Debug)
fmt.Printf(" 数据库:%s@%s:%d/%s\n",
loadedConfig.Database.User,
loadedConfig.Database.Host,
loadedConfig.Database.Port,
loadedConfig.Database.Database)
fmt.Printf(" 服务器端口:%d\n", loadedConfig.Server.Port)
fmt.Printf(" 功能:%v\n\n", loadedConfig.Features)
// 5. 显示原始 JSON
fmt.Println("4. 配置文件内容:")
content, _ := os.ReadFile("config.json")
fmt.Printf("%s\n", string(content))
// 6. 修改配置
fmt.Println("5. 修改配置:")
loadedConfig.App.Debug = true
loadedConfig.Server.Port = 9090
loadedConfig.Features = append(loadedConfig.Features, "feature3")
SaveConfig("config_updated.json", loadedConfig)
fmt.Println(" ✓ 配置已更新到 config_updated.json\n")
// 清理
os.Remove("config.json")
os.Remove("config_updated.json")
fmt.Println("✓ 配置文件处理示例完成")
}
输出:
=== 配置文件处理 ===
1. 创建默认配置:
2. 保存配置到 config.json:
✓ 配置已保存
3. 从 config.json 加载配置:
应用名称:MyApp
版本:1.0.0
调试模式:false
数据库:admin@localhost:5432/mydb
服务器端口:8080
功能:[feature1 feature2]
4. 配置文件内容:
{
"app": {
"name": "MyApp",
"version": "1.0.0",
"debug": false
},
"database": {
"host": "localhost",
"port": 5432,
"user": "admin",
"password": "secret",
"database": "mydb",
"ssl": false
},
"server": {
"host": "0.0.0.0",
"port": 8080,
"read_timeout": 30,
"write_timeout": 30,
"allowed_origins": [
"*"
]
},
"features": [
"feature1",
"feature2"
]
}
5. 修改配置:
✓ 配置已更新到 config_updated.json
✓ 配置文件处理示例完成
示例 9:UseNumber 处理大数字
package main
import (
"encoding/json"
"fmt"
"log"
"strings"
)
func main() {
fmt.Println("=== UseNumber 处理大数字 ===\n")
// 大数字 JSON
jsonStr := `{
"small": 123,
"large": 9223372036854775807,
"larger": 9223372036854775808,
"huge": 123456789012345678901234567890,
"float": 123.456
}`
// 1. 默认解码(使用 float64)
fmt.Println("1. 默认解码 (float64):")
var data1 map[string]interface{}
err := json.Unmarshal([]byte(jsonStr), &data1)
if err != nil {
log.Fatal(err)
}
for key, value := range data1 {
fmt.Printf(" %s: %v (类型:%T)\n", key, value, value)
}
// 检查精度丢失
fmt.Printf("\n 精度检查:\n")
large := data1["large"].(float64)
larger := data1["larger"].(float64)
fmt.Printf(" large == larger: %v (可能丢失精度)\n", large == larger)
// 2. 使用 UseNumber()
fmt.Println("\n2. 使用 UseNumber():")
decoder := json.NewDecoder(strings.NewReader(jsonStr))
decoder.UseNumber()
var data2 map[string]interface{}
err = decoder.Decode(&data2)
if err != nil {
log.Fatal(err)
}
for key, value := range data2 {
fmt.Printf(" %s: %v (类型:%T)\n", key, value, value)
}
// 3. 数字转换
fmt.Println("\n3. 数字转换:")
largeNum := data2["large"].(json.Number)
largerNum := data2["larger"].(json.Number)
hugeNum := data2["huge"].(json.Number)
// 转换为 int64
if i64, err := largeNum.Int64(); err == nil {
fmt.Printf(" large (int64): %d\n", i64)
} else {
fmt.Printf(" large (int64): 错误 - %v\n", err)
}
if i64, err := largerNum.Int64(); err == nil {
fmt.Printf(" larger (int64): %d\n", i64)
} else {
fmt.Printf(" larger (int64): 错误 - %v\n", err)
}
// 转换为 float64
if f64, err := largeNum.Float64(); err == nil {
fmt.Printf(" large (float64): %.0f\n", f64)
}
// 转换为字符串
fmt.Printf(" huge (string): %s\n", hugeNum.String())
// 4. 精度比较
fmt.Println("\n4. 精度比较:")
fmt.Printf(" 默认解码 large == larger: %v\n", large == larger)
fmt.Printf(" UseNumber large == larger: %v\n", largeNum.String() == largerNum.String())
fmt.Printf(" large: %s\n", largeNum.String())
fmt.Printf(" larger: %s\n", largerNum.String())
}
输出:
=== UseNumber 处理大数字 ===
1. 默认解码 (float64):
small: 123 (类型:float64)
large: 9.223372036854776e+18 (类型:float64)
larger: 9.223372036854776e+18 (类型:float64)
huge: 1.2345678901234568e+29 (类型:float64)
float: 123.456 (类型:float64)
精度检查:
large == larger: true (可能丢失精度)
2. 使用 UseNumber():
small: 123 (类型:json.Number)
large: 9223372036854775807 (类型:json.Number)
larger: 9223372036854775808 (类型:json.Number)
huge: 123456789012345678901234567890 (类型:json.Number)
float: 123.456 (类型:json.Number)
3. 数字转换:
large (int64): 9223372036854775807
larger (int64): 错误 - json: invalid number
large (float64): 9223372036854775807
huge (string): 123456789012345678901234567890
4. 精度比较:
默认解码 large == larger: true
UseNumber large == larger: false
large: 9223372036854775807
larger: 9223372036854775808
示例 10:Map 和 Slice 的高级用法
package main
import (
"encoding/json"
"fmt"
"log"
)
func main() {
fmt.Println("=== Map 和 Slice 高级用法 ===\n")
// 1. Map 的编解码
fmt.Println("1. Map 编解码:")
config := map[string]interface{}{
"name": "MyApp",
"version": "1.0.0",
"port": 8080,
"debug": true,
"features": []string{"auth", "logging", "cache"},
"database": map[string]interface{}{
"host": "localhost",
"port": 5432,
},
}
data, err := json.MarshalIndent(config, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Printf("编码:\n%s\n\n", string(data))
// 解码
var decoded map[string]interface{}
err = json.Unmarshal(data, &decoded)
if err != nil {
log.Fatal(err)
}
fmt.Printf("解码:\n")
fmt.Printf(" name: %s\n", decoded["name"])
fmt.Printf(" version: %s\n", decoded["version"])
fmt.Printf(" port: %v (类型:%T)\n", decoded["port"], decoded["port"])
fmt.Printf(" debug: %v (类型:%T)\n", decoded["debug"], decoded["debug"])
// 类型断言访问切片
if features, ok := decoded["features"].([]interface{}); ok {
fmt.Printf(" features: ")
for _, f := range features {
fmt.Printf("%s ", f.(string))
}
fmt.Println()
}
// 类型断言访问嵌套 map
if db, ok := decoded["database"].(map[string]interface{}); ok {
fmt.Printf(" database.host: %s\n", db["host"])
fmt.Printf(" database.port: %v\n", db["port"])
}
fmt.Println()
// 2. Slice 的编解码
fmt.Println("2. Slice 编解码:")
users := []map[string]interface{}{
{"id": 1, "name": "Alice", "email": "alice@example.com"},
{"id": 2, "name": "Bob", "email": "bob@example.com"},
{"id": 3, "name": "Charlie", "email": "charlie@example.com"},
}
data, err = json.MarshalIndent(users, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Printf("编码:\n%s\n\n", string(data))
// 解码
var decodedUsers []map[string]interface{}
err = json.Unmarshal(data, &decodedUsers)
if err != nil {
log.Fatal(err)
}
fmt.Printf("解码:\n")
for i, user := range decodedUsers {
fmt.Printf(" 用户 %d: %s (%s)\n",
i+1,
user["name"].(string),
user["email"].(string))
}
fmt.Println()
// 3. 有序 Map(使用切片保持顺序)
fmt.Println("3. 保持顺序:")
type KeyValue struct {
Key string `json:"key"`
Value interface{} `json:"value"`
}
orderedConfig := []KeyValue{
{Key: "z_last", Value: "Should be last"},
{Key: "a_first", Value: "Should be first"},
{Key: "m_middle", Value: "Should be middle"},
}
data, _ = json.MarshalIndent(orderedConfig, "", " ")
fmt.Printf("有序配置:\n%s\n\n", string(data))
// 4. 过滤 Map 字段
fmt.Println("4. 过滤 Map 字段:")
fullData := map[string]interface{}{
"public": "visible",
"private": "hidden",
"secret": "very_secret",
}
// 只导出公共字段
filtered := make(map[string]interface{})
for k, v := range fullData {
if k != "private" && k != "secret" {
filtered[k] = v
}
}
data, _ = json.MarshalIndent(filtered, "", " ")
fmt.Printf("过滤后:\n%s\n", string(data))
}
输出:
=== Map 和 Slice 高级用法 ===
1. Map 编解码:
编码:
{
"database": {
"host": "localhost",
"port": 5432
},
"debug": true,
"features": [
"auth",
"logging",
"cache"
],
"name": "MyApp",
"port": 8080,
"version": "1.0.0"
}
解码:
name: MyApp
version: 1.0.0
port: 8080 (类型:float64)
debug: true (类型:bool)
features: auth logging cache
database.host: localhost
database.port: 5432
2. Slice 编解码:
编码:
[
{
"id": 1,
"name": "Alice",
"email": "alice@example.com"
},
{
"id": 2,
"name": "Bob",
"email": "bob@example.com"
},
{
"id": 3,
"name": "Charlie",
"email": "charlie@example.com"
}
]
解码:
用户 1: Alice (alice@example.com)
用户 2: Bob (bob@example.com)
用户 3: Charlie (charlie@example.com)
3. 保持顺序:
有序配置:
[
{
"key": "z_last",
"value": "Should be last"
},
{
"key": "a_first",
"value": "Should be first"
},
{
"key": "m_middle",
"value": "Should be middle"
}
]
4. 过滤 Map 字段:
过滤后:
{
"public": "visible"
}
最佳实践
✅ 推荐做法
-
总是检查错误
// ✅ 推荐 data, err := json.Marshal(v) if err != nil { return err } err = json.Unmarshal(data, &v) if err != nil { return err } // ❌ 不推荐 data, _ := json.Marshal(v) json.Unmarshal(data, &v) -
使用指针接收解码
// ✅ 推荐 var user User err := json.Unmarshal(data, &user) // ❌ 错误 var user User err := json.Unmarshal(data, user) // 需要指针 -
使用 struct tag 自定义字段
// ✅ 推荐 type User struct { Name string `json:"name"` Email string `json:"email,omitempty"` } // ❌ 不推荐 type User struct { Name string // 默认使用字段名 Email string } -
大数字使用 UseNumber()
// ✅ 推荐:处理大数字或需要精度 decoder := json.NewDecoder(reader) decoder.UseNumber() // ❌ 不推荐:可能丢失精度 var data map[string]interface{} json.Unmarshal(jsonData, &data) // 数字转为 float64 -
流式处理大文件
// ✅ 推荐:大文件 decoder := json.NewDecoder(file) for decoder.More() { var item Item decoder.Decode(&item) } // ❌ 不推荐:可能内存溢出 data, _ := io.ReadAll(file) json.Unmarshal(data, &items) -
使用 json.Number 处理数字
// ✅ 推荐 num := data["count"].(json.Number) intVal, _ := num.Int64() // ❌ 不推荐 num := data["count"].(float64) // 可能丢失精度
❌ 不安全做法
-
不要忽略类型断言
// ❌ 错误 value := data["key"].(string) // 可能 panic // ✅ 正确 value, ok := data["key"].(string) if !ok { // 处理类型不匹配 } -
不要信任输入数据
// ❌ 错误 var user User json.Unmarshal(input, &user) // 未验证 // ✅ 正确 var user User if err := json.Unmarshal(input, &user); err != nil { return err } // 验证 user 字段 -
不要编码敏感数据
// ❌ 错误 type User struct { Name string `json:"name"` Password string `json:"password"` // 危险! } // ✅ 正确 type User struct { Name string `json:"name"` Password string `json:"-"` // 不编码 }
性能优化
1. 使用 MarshalIndent 代替手动格式化
// ✅ 推荐
data, _ := json.MarshalIndent(v, "", " ")
// ❌ 不推荐
data, _ := json.Marshal(v)
// 然后手动格式化
2. 预分配切片
// ✅ 推荐
items := make([]Item, 0, expectedCount)
json.Unmarshal(data, &items)
// ❌ 不推荐
var items []Item
json.Unmarshal(data, &items)
3. 重用 Encoder/Decoder
// ✅ 推荐:重用
encoder := json.NewEncoder(buf)
for _, item := range items {
encoder.Encode(item)
}
// ❌ 不推荐:重复创建
for _, item := range items {
json.NewEncoder(buf).Encode(item)
}
4. 使用 omitempty 减少大小
// ✅ 推荐
type User struct {
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
}
// 零值字段不会被编码
总结
核心函数
| 函数 | 用途 | 返回值 |
|---|---|---|
| Marshal | 编码为 JSON | []byte, error |
| MarshalIndent | 格式化编码 | []byte, error |
| Unmarshal | 从 JSON 解码 | error |
| Valid | 验证 JSON | bool |
| HTMLEscape | HTML 转义 | - |
核心类型
| 类型 | 用途 | 说明 |
|---|---|---|
| Encoder | 流式编码 | json.NewEncoder(w) |
| Decoder | 流式解码 | json.NewDecoder(r) |
| RawMessage | 原始 JSON | 延迟解码 |
| Number | JSON 数字 | 保持精度 |
| Token | JSON Token | 对象/数组边界 |
Struct Tag 选项
| 选项 | 说明 | 示例 |
|---|---|---|
| 字段名 | 自定义键名 | json:"name" |
| omitempty | 零值忽略 | json:"name,omitempty" |
| string | 数字转字符串 | json:"age,string" |
| - | 忽略字段 | json:"-" |
类型映射
| Go 类型 | JSON 类型 |
|---|---|
| int, float | number |
| string | string |
| []T, map[K]V | array, object |
| bool | boolean |
| nil, nil pointer | null |
常见错误
| 错误 | 原因 | 解决方法 |
|---|---|---|
| invalid character | JSON 语法错误 | 检查 JSON 格式 |
| cannot unmarshal | 类型不匹配 | 检查类型定义 |
| unexpected end | JSON 不完整 | 检查数据完整性 |
参考资料
最后更新:2026-04-03
Go 版本:Go 1.23+