当前位置: 首页 > news >正文

吃透 Golang 基础:使用 encoding/json 实现 Golang 数据结构与 JSON 对象的转换

文章目录

  • 使用 encoding/json 实现 Golang 数据结构与 JSON 对象的转换
    • Marshal:将 struct 编码为 JSON 对象
    • Unmarshal:将 JSON 对象解码
    • 实践:以 Gin 框架为例

使用 encoding/json 实现 Golang 数据结构与 JSON 对象的转换

在这里插入图片描述
JSON 是 JavaScript 对象表示法,是非常常用的发送和接收结构化信息的标准协议。(除了 JSON,还有 XML 和 Google 的 Protobuf 等通信协议)

Go 对于各种标准编解码协议都有着良好的支持,本节对encoding/json包的用法进行概述。

JSON 是对 JavaScript 中各种类型的值——字符串、数字、布尔值和对象进行 Unicode 编码。它可以用有效可读的方式表示基础数据类型(整型/浮点型/字节/字符串等)和复合类型(数组、slice、结构体、map 等)。

基本的 JSON 类型有数字、布尔值、字符串,字符串是以双引号包含的 Unicode 字符序列,支持 Go 类似的反斜杠转义。

简单来说,在 Go 中使用 JSON 有以下注意事项:

  • 基础类型可以通过 JSON 的数组和对象类型进行递归组合;
  • 一个 JSON 数组是一个有序的值序列,写在一个方括号中以逗号分隔;
  • 一个 JSON 数组可以用于编码 GO 的数组和 slice;
  • 一个 JSON 对象是一个字符串到值的映射,写成一系列key:value的形式,用花括号包含并以逗号分隔;
  • JSON 的对象类型可以用于编码 Go 当中的 map 类型和结构体

Marshal:将 struct 编码为 JSON 对象

下例以“收集各种电影评论并提供反馈功能”为场景,演示了如何将 Go 的 struct 转为 JSON 对象:

type Movie struct {Title 	stringYear 	int `json:"released"`			// 使用`...`作为JSON与struct转换的tagColor 	bool `json:"color,omitempty"`Actors 	[]string
}var movies = []Movie{{Title: "Casablanca", Year: 1942, Color: false,Actors: []string{"Humphrey Bogart", "Ingrid Bergman"}},{Title: "Cool Hand Luke", Year: 1967, Color: true,Actors: []string{"Paul Newman"}},{Title: "Bullitt", Year: 1968, Color: true,Actors: []string{"Steve McQueen", "Jacqueline Bisset"}},// ...
}	// 定义一个Movie的slice

上面这种数据结构类型非常适合 JSON 格式,并且在二者之间互相转换也比较容易。将 Go 当中类似 movies 的结构体 slice 转为 JSON 的过程叫做编组(marshaling),可以直接通过encoding/json包中的json.Marshal函数完成:

data, err := json.Marshal(movies)
if err != nil {log.Fatalf("JSON marshaling failed: %v", err.Error())
}
fmt.Printf("%s\n", data)

Marshal 返回一个编码后的字节 slice,它是很长的字符串,没有空白缩进:

[{"Title":"Casablanca","released":1942,"Actors":["Humphrey Bogart","Ingr
id Bergman"]},{"Title":"Cool Hand Luke","released":1967,"color":true,"Ac
tors":["Paul Newman"]},{"Title":"Bullitt","released":1968,"color":true,"
Actors":["Steve McQueen","Jacqueline Bisset"]}]

上述这种紧凑的表示形式虽然包含了全部的信息,但是很难阅读(如果直接在浏览器输出 JSON 风格的字符串,以 Edge 浏览器为例,可以直接打开“紧凑显示”,浏览器会自动帮我们把 JSON 字符串转为可阅读的格式)。为了生成便于阅读的格式,可以用json.MarshalIndent产生整齐缩进:

data, err := json.MarshalIndent(movies, "", "    ")
if err != nil {log.Fatalf("JSON marshaling failed: %s", err)
}
fmt.Printf("%s\n", data)
// output:
[{"Title": "Casablanca","released": 1942,"Actors": ["Humphrey Bogart","Ingrid Bergman"]},{"Title": "Cool Hand Luke","released": 1967,"color": true,"Actors": ["Paul Newman"]},{"Title": "Bullitt","released": 1968,"color": true,"Actors": ["Steve McQueen","Jacqueline Bisset"]}
]
// 问题在于, 加入缩进之后字符串占用的传输空间更大, 增加了传输压力

编码时,默认使用 Go 结构体成员的名字作为 JSON 对象中key:value的 key(通过反射技术来实现)。只有导出的结构体成员才会被编码。

在定义结构体时,我们可以通过...加入 tag,以告知在将 struct 转为 json 时,json 中key的值是否需要改变,以及在解码时,将 json 对象的key与 Go 的 struct 当中的成员对应起来:

Year  int  `json:"released"`
Color bool `json:"color,omitempty"`
// ⬆️ omitempty 表示当 Go 结构体成员为空或为零值时, 不生成该 JSON 对象

Unmarshal:将 JSON 对象解码

编码的逆操作是解码,将 JSON 数据解码为 Go 的某个数据结构。在 Go 当中通过json.Unmarshal来完成。

下例将 JSON 格式的电影数据解码到一个 struct slice 当中,该 struct 只有 Title 成员。通过定义合适的 Go 数据结构,可以选择性地解码 JSON 中我们感兴趣的成员,而我们不感兴趣的成员将被忽略。下例中,当 Unmarshal 函数调用返回时,只有 Title 的值会被捕获,而其他 JSON 成员会被丢失。

var titles []struct{ Title string }
if err := json.Unmarshal(data, &titles); err != nil {log.Fatalf("JSON unmarshaling failed: %s", err)
}
fmt.Println(titles)	// "[{Casablanca} {Cool Hand Luke} {Bullitt}]"

另外,encoding/json还提供了json.Encoderjson.Decoder来针对输出/输入流编解码 JSON 对象。

实践:以 Gin 框架为例

在开发 Web 项目时,我们通常不会直接基于 Go 的 net 库进行开发,而是使用现成的 Web 框架,比如 Gin 框架。

常见的 Web 应用使用 RESTful API 在前端和后端之间传递数据,也就是说,对于 Go 后端,我们需要根据接口的要求生成 JSON 对象作为 HTTP Request 的 Response。而如果前端涉及到表单提交,通过 HTTP POST 传递给后端的数据同样也是 JSON 结构的对象。

在 Gin 框架当中,封装好了现成的面向 HTTP 报文的 JSON 编解码工具,使用c.ShouldBindJSON可以将 HTTP Body 当中的字符串与 Go struct 相绑定,而使用c.JSON可以直接将传入的 struct 转为 JSON 结构的字符串。

一个使用c.ShouldBindJSON处理 Post 请求的例子如下:

// ... ... ...
if err := c.ShouldBindJSON(&categoryForm); err != nil {api.HandleValidatorError(c, err)return
}
// ... ... ...

一个使用c.JSON返回 JSON 结构的 HTTP Response 的例子如下:

// ... ... ...
rsp, err := goodsClient.CreateGoods(context.Background(), &proto.CreateGoodsInfo{Name:            goodsForm.Name, GoodsSn:         goodsForm.GoodsSn,Stocks:          goodsForm.Stocks,MarketPrice:     goodsForm.MarketPrice,ShopPrice:       goodsForm.ShopPrice,GoodsBrief:      goodsForm.GoodsBrief,ShipFree:        *goodsForm.ShipFree,Images:          goodsForm.Images,DescImages:      goodsForm.DescImages,GoodsFrontImage: goodsForm.FrontImage,CategoryId:      goodsForm.CategoryId,BrandId:         goodsForm.Brand,
})
if err != nil {api.HandleGrpcErrorToHTTP(err, c)return
}
c.JSON(http.StatusOK, rsp)
// ... ... ...

相关文章:

  • go语言学习 第6章:错误处理
  • 《架构即未来》笔记
  • usbutils工具的使用帮助
  • Spring AI 入门:Java 开发者的生成式 AI 实践之路
  • ADC初始化过程中的——校准
  • Ubuntu18.6 学习QT问题记录以及虚拟机安装Ubuntu后的设置
  • 强化学习基础概念图文版笔记
  • Android动态广播注册收发原理
  • 【Go语言基础【7】】条件语句
  • Redux 实践与中间件应用
  • GitHub 趋势日报 (2025年06月05日)
  • 数据结构之LinkedList
  • day23 pipeline管道
  • Web前端基础:HTML-CSS
  • win10+TensorRT+OpenCV+Qt+YOLOV8模型部署教程
  • 2025年我国数字经济产业发展概述
  • uniapp Vue2 获取电量的独家方法:绕过官方插件限制
  • vscode使用系列之快速生成html模板
  • ubuntu 22 安装milvus
  • vue-20(Vuex 状态管理的最佳实践)
  • 网站售后服务模板/百度账号怎么改名字
  • 网站建设 代理/百度指数大数据
  • 安溪网站开发/公司如何在百度宣传
  • 免费网站建设平台哪个好/网店运营工作内容
  • 做下载网站用阿里云的什么产品/百度上首页
  • 做网站学/口碑营销有哪些