Go语言结构体与JSON互转详解:从生成到解析的完整指南
本文详细解析Golang中`encoding/json`包的应用,涵盖从结构体格式化序列化、Map动态构建,到反向解析回结构体及泛型Map的完整流程,提供可直接复用的代码示例。
使用结构体生成JSON
在Go语言中,最规范的JSON生成方式是将数据封装为结构体(Struct),并通过`encoding/json`包进行序列化。为了生成人类可读的多行JSON文本,通常推荐使用json.MarshalIndent函数,它支持自定义缩进格式。
结构体中的标签(Tag)对JSON输出起着决定性作用:
`json:"-"`:表示该字段不输出到JSON中。`json:",string"`:强制将数值类型编码为JSON字符串形式,常用于前端JS接收避免精度丢失。`json:"fieldname"`:指定输出的键名,若未指定则默认使用字段名(首字母小写)。
package main
import (
"encoding/json"
"fmt"
)
// 成员变量名首字母必须大写才能被JSON包访问
type IT struct {
Company string `json:"-"` //此字段不会输出到屏幕
Subjects []string `json:"subjects"` //自定义Key
IsOk bool `json:",string"` //bool值转为字符串"true"
Price float64 `json:",string"` //浮点值转为字符串
}
func main() {
//定义一个结构体变量,同时初始化
s := IT{"itcast", []string{"Go", "C++", "Python", "Test"}, true, 666.666}
//使用 MarshalIndent 进行格式化编码,第二个参数为前缀(空),第三个为制表符
buf, err := json.MarshalIndent(s, "", "\t")
if err != nil {
fmt.Println("err = ", err)
return
}
fmt.Println(string(buf))
}
使用Map动态生成JSON
当数据结构不固定或需要动态添加字段时,可以使用map[string]interface{}作为中间容器。这种方法灵活性高,但需要注意Map遍历时的无序性可能导致JSON键的顺序变化。
package main
import (
"encoding/json"
"fmt"
)
func main() {
//创建一个map
m := make(map[string]interface{}, 4)
m["company"] = "itcast"
m["subjects"] = []string{"Go", "C++", "Python", "Test"}
m["isok"] = true
m["price"] = 666.666
//编码成json
result, err := json.MarshalIndent(m, "", "\t")
if err != nil {
fmt.Println("err = ", err)
return
}
fmt.Println("result = ", string(result))
}
JSON解析到结构体
反序列化通常用于读取API响应或配置文件。目标结构体的字段必须是导出的(首字母大写),且最好包含json:标签以精确匹配JSON Key,否则需确保JSON Key与结构体字段名一致(忽略大小写)。
注意:json.Unmarshal的第二个参数必须是结构体变量的地址指针(如&tmp),以便写入解析结果。
package main
import (
"encoding/json"
"fmt"
)
type IT struct {
Company string `json:"company"`
Subjects []string `json:"subjects"`
IsOk bool `json:"isok"`
Price float64 `json:"price"`
}
func main() {
jsonBuf := `
{
"company": "itcast",
"subjects": [
"Go",
"C++",
"Python",
"Test"
],
"isok": true,
"price": 666.666
}`
var tmp IT
err := json.Unmarshal([]byte(jsonBuf), &tmp)
if err != nil {
fmt.Println("err = ", err)
return
}
fmt.Printf("tmp = %+v\n", tmp)
//只解析部分字段示例
type IT2 struct {
Subjects []string `json:"subjects"`
}
var tmp2 IT2
err = json.Unmarshal([]byte(jsonBuf), &tmp2)
if err != nil {
fmt.Println("err = ", err)
return
}
fmt.Printf("tmp2 = %+v\n", tmp2)
}
JSON解析到Map并提取数据
如果不需要强类型约束,可以将JSON直接解析为map[string]interface{}。由于Go是静态类型语言,Map中的值类型为interface{},使用时必须进行类型断言才能获取原始数据。
Go标准库中没有直接的String slice类型,JSON数组解码后通常会变成[]interface{},这点需要特别注意。
package main
import (
"encoding/json"
"fmt"
)
func main() {
jsonBuf := `
{
"company": "itcast",
"subjects": [
"Go",
"C++",
"Python",
"Test"
],
"isok": true,
"price": 666.666
}`
//创建一个map接收解析结果
m := make(map[string]interface{}, 4)
err := json.Unmarshal([]byte(jsonBuf), &m)
if err != nil {
fmt.Println("err = ", err)
return
}
fmt.Printf("raw map = %+v\n", m)
//遍历并使用switch-case进行类型断言
for key, value := range m {
switch data := value.(type) {
case string:
fmt.Printf("map[%s]的值类型为string, value = %s\n", key, data)
case bool:
fmt.Printf("map[%s]的值类型为bool, value = %v\n", key, data)
case float64:
fmt.Printf("map[%s]的值类型为float64, value = %f\n", key, data)
// JSON数字在Go中都解码为float64
case []interface{}:
fmt.Printf("map[%s]的值类型为数组, 长度: %d\n", key, len(data))
//如果需要进一步处理数组内的具体元素,可再次迭代
default:
fmt.Printf("map[%s]的类型未知\n", key)
}
}
}
以上就是Go语言结构体与JSON互转的详细内容,更多关于Go语言JSON操作技巧的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













