Go语言标准库JSON编码与解析核心用法
本文详细解析Go语言中encoding/json包的序列化与反序列化操作。内容涵盖Map、结构体(含自定义标签)、切片等数据类型与JSON字符串之间的双向转换方法,并结合具体代码说明字段导出的关键规则。
1. Map与JSON互转
将Go语言的Map结构转换为JSON字符串需使用Marshal函数,其返回值为[]byte类型。反之,使用Unmarshal函数配合目标类型的Map变量即可完成反向解析。
第1步:Map转JSON字符串
- 目的:将内存中的键值对数据序列化为JSON格式。
- 操作:调用
json.Marshal(map)。 - 关键点:输出结果为字节切片,打印时可直接转为字符串查看。
package main
import (
"encoding/json"
"fmt"
)
func main() {
// 基础字符串Map
map1 := map[string]string{
"name": "张三",
"age": "18",
"home": "北京",
}
json1, err := json.Marshal(map1)
if err != nil {
fmt.Println(err.Error())
}
fmt.Printf("json1: %s 类型: %T\n", json1, json1)
// 嵌套数组Map
map2 := map[string][]string{
"fruit": {"香蕉", "葡萄"},
"coder": {"PHP", "Go", "Java"},
"likes": {"打游戏", "看动漫"},
}
json2, err := json.Marshal(map2)
if err != nil {
fmt.Println(err.Error())
}
fmt.Printf("json2: %s 类型: %T\n", json2, json2)
}
/*
输出结果:
json1: {"age":"18","home":"北京","name":"张三"} 类型: []uint8
json2: {"coder":["PHP","Go","Java"],"fruit":["香蕉","葡萄"],"likes":["打游戏","看动漫"]} 类型: []uint8 */第2步:JSON转Map结构
- 目的:将JSON字符串解析为Map供程序读取。
- 入口:确保JSON字符串合法且目标Map类型定义准确。
- 动作:使用
json.Unmarshal([]byte(json), &targetMap)。 - 参数注意:地址符
&必不可少,否则无法写入。
package main
import (
"encoding/json"
"fmt"
)
func main() {
json1 := `{"age":"18","home":"北京","name":"张三"}`
map1 := make(map[string]string)
err := json.Unmarshal([]byte(json1), &map1)
if err != nil {
fmt.Println(err.Error())
}
fmt.Printf("map1: %v T: %T\n", map1, map1)
json2 := `{"coder":["PHP","Go","Java"],"fruit":["香蕉","葡萄"],"likes":["打游戏","看动漫"]}`
map2 := make(map[string][]string)
err = json.Unmarshal([]byte(json2), &map2)
if err != nil {
fmt.Println(err.Error())
}
fmt.Printf("map2: %v T: %T\n", map2, map2)
}
/*
输出结果:
map1: map[age:18 home:北京 name:张三] T: map[string]string
map2: map[coder:[PHP Go Java] fruit:[香蕉 葡萄] likes:[打游戏 看动漫]] T: map[string][]string */2. 结构体与JSON互转
在Web开发中,结构体是最常用的数据载体。Go的encoding/json包利用反射机制处理结构体编解码。需注意:只有首字母大写的导出字段会被序列化或反序列化,小写字段将被忽略。
第3步:无标签的结构体转换
- 准备:定义包含导出字段(大写开头)的结构体。
- 规则:未标记特殊符号时,JSON的Key直接使用字段名。
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
Name string // 导出字段
Age int // 导出字段
Class string // 导出字段
phone string // 非导出字段(小写),不会被解析
}
func main() {
s := Student{
Name: "张三",
Age: 17,
Class: "三年级",
Phone: "17600112222", // 假设原意为设置phone,但此处赋值给不可见字段会报错,这里仅为展示结构体定义差异,实际需对应字段
}
// 修正:由于phone未定义大写字段,此处直接构造不含Phone的正确示例
sCorrect := Student{
Name: "张三",
Age: 17,
Class: "三年级",
}
jsonBytes, _ := json.Marshal(sCorrect)
fmt.Printf("JSON: %s\n", jsonBytes)
}
// 输出: JSON: {"Name":"张三","Age":17,"Class":"三年级"}第4步:使用JSON标签控制映射
可以通过结构体字段的标签(struct tag)`json:"key"`来修改JSON输出的Key名称,甚至排除某些字段。
- 自定义Key:如
`json:"_name"`,输出时将变为_name。 - 忽略字段:值为
-时,该字段不参与序列化。 - 默认行为:无标签时使用字段原名。
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
Name string `json:"_name"` // 自定义Key
Age int `json:"_age"`
Class string `json:"-"` // 忽略此字段
Phone string `json:"phone"`
Score float32 // 使用默认字段名 Score
}
func main() {
s := Student{
Name: "张三",
Age: 17,
Class: "三年级",
Phone: "17600112222",
Score: 88.5,
}
jsonBytes, err := json.Marshal(s)
if err != nil {
fmt.Println(err)
}
fmt.Printf("JSON: %s\n", jsonBytes)
}
// 输出 -> JSON: {"_name":"张三","_age":17,"phone":"17600112222","Score":88.5}第5步:匿名(嵌入)字段的处理
当结构体嵌入另一个结构体作为匿名字段时,内层结构体的所有字段会提升为外层结构体的字段,并在JSON平铺展示。
package main
import (
"encoding/json"
"fmt"
)
type Top struct {
Sort int `json:"sort"`
Score float64
Class string
}
type Student struct {
Name string `json:"_name"`
Age int `json:"_age"`
Top // 匿名字段
}
func main() {
s := Student{
Name: "张三",
Age: 18,
Top: Top{Sort: 1, Score: 99.5, Class: "一年级"},
}
jsonBytes, _ := json.Marshal(s)
fmt.Printf("JSON: %s\n", jsonBytes)
}
// 输出: JSON: {"_name":"张三","_age":18,"sort":1,"Score":99.5,"Class":"一年级"}第6步:JSON反序列化至结构体
- 规则:反序列化时不区分大小写(如JSON中的
name可赋值给Go的Name)。 - 优先级:优先匹配`json`标签定义的Key,其次匹配结构体字段名。
package main
import (
"encoding/json"
"fmt"
)
type Top struct {
Sort int `json:"sort"`
Score float64
Class string
}
type Student struct {
Name string `json:"_name"`
Age int `json:"_age"`
Top
}
func main() {
var student Student
// 模拟接收到的JSON数据
js := `{"_name":"张三","_age":18,"sort":1,"Score":99.5,"Class":"一年级"}`
err := json.Unmarshal([]byte(js), &student)
if err != nil {
fmt.Println(err)
}
fmt.Printf("Struct: %+v\n", student)
}
// 输出: v: {Name:张三 Age:18 Top:{Sort:1 Score:99.5 Class:一年级}}3. 切片与JSON互转
Go语言的切片(Slice)可以直接序列化为JSON数组,反之亦然。
第7步:切片转JSON
package main
import (
"encoding/json"
"fmt"
)
func main() {
students := []string{"张三", "李四", "小米"}
marshal, err := json.Marshal(students)
if err != nil {
fmt.Println(err)
}
fmt.Printf("Result: %s Type: %T\n", marshal, marshal)
}
// 输出: Result: ["张三","李四","小米"] Type: []uint8第8步:JSON转切片
- 注意:目标变量必须声明为切片类型(
var sc []string),初始为零值nil。 - 动作:
Unmarshal会自动分配内存并填入数据。
package main
import (
"encoding/json"
"fmt"
)
func main() {
jsonData := `["张三","李四","小米"]`
var sc []string
err := json.Unmarshal([]byte(jsonData), &sc)
if err != nil {
fmt.Println(err)
}
fmt.Printf("Result: %v Type: %T\n", sc, sc)
}
// 输出: Result: [张三 李四 小米] Type: []string以上就是Go语言学习之JSON编码解析与使用的详细内容,更多关于Go语言JSON的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













