Go 语言 JSON 序列化/反序列化:Tag 用法完全指南

Go 语言 JSON 序列化/反序列化:Tag 用法完全指南

在 Go 语言处理 JSON 时,struct tag(结构体标签) 是核心工具,它能精准控制结构体与 JSON 之间的序列化(Go → JSON)和反序列化(JSON → Go)规则,解决字段名映射、忽略字段、空值处理、嵌套结构等常见问题。

本文从基础到实战,全面讲解 Go JSON tag 的用法、常用参数和最佳实践,每个代码示例都附带运行结果 + 通俗解释,新手也能直接看懂。


一、什么是 Go JSON Tag?

JSON tag 是结构体字段后方反引号``包裹的元信息 ,标准库 encoding/json 会解析这个标签,决定 JSON 与结构体的转换规则。

基础格式

go 复制代码
FieldName Type `json:"key_name,option"`
  • key_name:JSON 中的键名(自定义映射)
  • option:可选参数(控制序列化/反序列化行为)

二、最核心:字段名映射(默认规则 vs 自定义)

1. 默认规则(无 tag)

Go 结构体字段必须大写(导出) ,否则 json 包无法访问;

默认会将结构体字段名原样输出为 JSON 键。

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
)

// 无 tag 示例
type User struct {
	UserName string // JSON: "UserName"
	Age      int    // JSON: "Age"
}

func main() {
	u := User{UserName: "张三", Age: 20}
	bytes, _ := json.Marshal(u)
	fmt.Println(string(bytes))
}

运行结果

复制代码
{"UserName":"张三","Age":20}

结果解释

  1. 没有写 tag,JSON 键名完全和结构体字段名一致
  2. UserName → JSON UserNameAge → JSON Age
  3. 结构体赋值的内容,原样转为 JSON 键值对。

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

使用 json:"自定义名称" 强制指定 JSON 键,解决前后端字段命名不一致问题。

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	UserName string `json:"username"` // JSON 键:username
	Age      int    `json:"user_age"`  // JSON 键:user_age
}

func main() {
	u := User{UserName: "张三", Age: 20}
	bytes, _ := json.Marshal(u)
	fmt.Println(string(bytes))
}

运行结果

复制代码
{"username":"张三","user_age":20}

结果解释

  1. tag 生效了,结构体字段名被替换成我们指定的名称
  2. UserNameusernameAgeuser_age
  3. 这是前后端对接最常用的功能,统一命名规范。

三、JSON Tag 常用可选参数(高频实用)

1. omitempty:忽略空值

序列化时,字段为零值(空字符串、0、false、nil 切片/map),不输出到 JSON。

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	UserName string `json:"username,omitempty"`
	Age      int    `json:"age,omitempty"`
}

func main() {
	u := User{UserName: ""} // 空字符串 + 0
	bytes, _ := json.Marshal(u)
	fmt.Println(string(bytes))
}

运行结果

复制代码
{}

结果解释

  1. UserName 是空字符串,Age 是默认值 0,都属于空值
  2. omitempty 作用:空值不输出到 JSON
  3. 最终 JSON 为空对象 {},精简了无用数据。

2. -:完全忽略字段

序列化不输出 ,反序列化不读取,用于隐藏密码等敏感字段。

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	UserName string `json:"username"`
	Password string `json:"-"` // 永远不参与 JSON 转换
}

func main() {
	u := User{UserName: "张三", Password: "123456"}
	bytes, _ := json.Marshal(u)
	fmt.Println(string(bytes))
}

运行结果

复制代码
{"username":"张三"}

结果解释

  1. 结构体有 Password 字段,且赋值了 123456
  2. json:"-" 作用:无论值是什么,都不转成 JSON
  3. 最终结果没有密码,保护敏感信息。

3. string:强制类型转换

将 Go 数字/布尔型,转为 JSON 字符串类型(适配前端类型要求)。

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	Age  int    `json:"age,string"` // Go int → JSON "20"
	Flag bool   `json:"flag,string"` // Go bool → JSON "true"
}

func main() {
	u := User{Age: 20, Flag: true}
	bytes, _ := json.Marshal(u)
	fmt.Println(string(bytes))
}

运行结果

复制代码
{"age":"20","flag":"true"}

结果解释

  1. Go 里 Age 是数字 20string 强制转成 JSON 字符串 "20"
  2. Go 里 Flag 是布尔值 true,转成 JSON 字符串 "true"
  3. 解决前后端类型不匹配的问题。

四、进阶:嵌套结构体与 Tag 配合

1. 普通嵌套

结构体套结构体,默认转成 JSON 嵌套对象。

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
)

type Profile struct {
	Address string `json:"address"`
}

type User struct {
	Name    string  `json:"username"`
	Profile Profile `json:"profile"` // 嵌套对象
}

func main() {
	u := User{Name: "张三", Profile: Profile{Address: "北京"}}
	bytes, _ := json.Marshal(u)
	fmt.Println(string(bytes))
}

运行结果

复制代码
{"username":"张三","profile":{"address":"北京"}}

结果解释

  1. 结构体嵌套 → JSON 对象嵌套;
  2. Profile 结构体 → JSON 里的 profile 对象;
  3. 层级结构和结构体完全一致。

2. inline:扁平化展开(无嵌套)

去掉嵌套层级,把内部结构体字段直接展开到外层。

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
)

type Profile struct {
	Address string `json:"address"`
}

type User struct {
	Name    string  `json:"username"`
	Profile `json:",inline"` // 扁平化
}

func main() {
	u := User{Name: "张三", Profile: Profile{Address: "北京"}}
	bytes, _ := json.Marshal(u)
	fmt.Println(string(bytes))
}

运行结果

复制代码
{"username":"张三","address":"北京"}

结果解释

  1. inline 作用:拆掉嵌套,字段平铺
  2. 没有 profile 对象了,address 直接和 username 同级;
  3. 适合不需要层级、简化 JSON 的场景。

五、完整实战示例(序列化 + 反序列化)

集合所有 tag 用法,一站式掌握。

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
)

// 定义结构体 + 完整 Tag
type Employee struct {
	Name     string   `json:"emp_name"`
	Age      int      `json:"emp_age,string"`
	Salary   float64  `json:"salary,omitempty"`
	Password string   `json:"-"`
	Hobbies  []string `json:"hobbies"`
}

func main() {
	// 1. 序列化:Go → JSON
	emp := Employee{
		Name:    "李四",
		Age:     25,
		Hobbies: []string{"跑步", "编程"},
	}
	data, _ := json.MarshalIndent(emp, "", "  ")
	fmt.Println("序列化结果:")
	fmt.Println(string(data))

	// 2. 反序列化:JSON → Go
	jsonStr := `{"emp_name":"李四","emp_age":"25","hobbies":["跑步","编程"]}`
	var emp2 Employee
	_ = json.Unmarshal([]byte(jsonStr), &emp2)
	fmt.Println("\n反序列化结果:")
	fmt.Printf("姓名:%s,年龄:%d\n", emp2.Name, emp2.Age)
}

运行结果

复制代码
序列化结果:
{
  "emp_name": "李四",
  "emp_age": "25",
  "hobbies": [
    "跑步",
    "编程"
  ]
}

反序列化结果:
姓名:李四,年龄:25

结果解释

  1. 序列化:自定义键名、数字转字符串、忽略空值、隐藏密码全部生效;
  2. 反序列化:JSON 能正确转回结构体,tag 规则双向生效;
  3. 这就是项目中最常用的完整写法。

六、Tag 必知规则(避坑指南)

  1. 结构体字段必须大写(导出字段),小写字段无论加什么 Tag 都无效;
  2. Tag 语法严格:无空格 ,逗号分隔参数(json:"name,omitempty");
  3. 多个参数顺序无关:json:"age,string,omitempty" 等价于 json:"age,omitempty,string"
  4. 反序列化时,JSON 键不区分大小写,但推荐严格匹配 Tag 名称。

七、常用 Tag 参数速查表

Tag 写法 作用
json:"name" 自定义 JSON 键名
json:"name,omitempty" 自定义键名 + 空值忽略
json:"-" 完全忽略字段
json:"name,string" 强制转为 JSON 字符串
json:",inline" 嵌套结构扁平化

总结

Go 的 JSON Tag 是处理 JSON 转换的核心利器

  • json:"key" 解决字段名映射;
  • omitempty 精简空值;
  • - 隐藏敏感字段;
  • string 适配类型差异。

掌握这些用法,就能轻松应对 Go 项目中 99% 的 JSON 序列化/反序列化场景!

相关推荐
小肝一下13 小时前
STL——list
开发语言·c++·stl·list·伊雷娜
前网易架构师-高司机13 小时前
ROS2 Jazzy+Gazebo Harmonic 环境下,用 URDF 搭建机器人,配置物理属性、插件与桥接,修复车轮和激光雷达故障 (手把手保姆级教程)
开发语言·算法·golang·机器人·ros
meilindehuzi_a13 小时前
深入浅出 JavaScript 核心:从底层内存与编译阶段彻底看透 var、let、const
开发语言·javascript·ecmascript
Python+9913 小时前
C++ 注解(注释)完整讲解
java·开发语言·c++
Reisentyan13 小时前
[Review]GoLang Learn Data Day 3
java·开发语言·golang
H_老邪13 小时前
Java基础-Java 核心语法与面向对象(底层原理级)篇
java·开发语言
承渊政道13 小时前
我的创作纪念日写在创作第256天:从第一篇C语言博客,到一路向前的自己!
c语言·开发语言·笔记·学习·学习方法
山有木兮啊13 小时前
Windows C++ 跨 CRT 内存管理与安全释放
开发语言·c++·windows
lly20240614 小时前
Linux Memcached 安装指南
开发语言