Go语言标准库JSON编码与解析核心用法

青禾
青禾
发布时间:2026-10-15 | 5人浏览过
原创

本文详细解析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的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表