使用 encoding/json 处理结构体
本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 76 课,共 107 课。
encoding/json 包可以让你将 Go 结构体转换为 JSON,也可以将 JSON 转回 Go 结构体。这对于 API、配置文件和数据存储至关重要。结构体标签控制字段与 JSON 键的映射方式。
要将结构体转换为 JSON,请使用 json.Marshal:
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}
func main() {
user := User{Name: "Alice", Email: "alice@example.com", Age: 30}
data, _ := json.Marshal(user)
fmt.Println(string(data))
// {"name":"Alice","email":"alice@example.com","age":30}
}像 `json:"name"` 这样的结构体标签用于指定 JSON 键名。没有标签时,Go 会直接使用字段名。只有导出的字段(首字母大写)才会包含在 JSON 输出中。
要将 JSON 转换回结构体,请使用 json.Unmarshal:
jsonStr := `{"name":"Bob","email":"bob@example.com","age":25}`
var user User
json.Unmarshal([]byte(jsonStr), &user)
fmt.Println(user.Name) // Bob常见的标签选项包括 omitempty,用于跳过零值,以及 -,用于完全忽略字段:
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
Price float64 `json:"price,omitempty"`
Internal string `json:"-"`
}使用 omitempty 时,如果 Price 为零,它就不会出现在 JSON 中。无论 Internal 字段的值是什么,它都不会被包含在内。
挑战
简单让我们构建一个电影目录系统,在 Go 结构体和 JSON 之间进行转换!你将练习把结构体编码为 JSON,以及把 JSON 解码回结构体,并使用结构体标签控制 JSON 字段名称。
你将把代码分成两个文件:
movie.go:定义电影数据模型,并添加合适的 JSON 标签。创建一个
Movie结构体,包含以下字段和 JSON 映射:Title(string)映射到"title"Director(string)映射到"director"Year(int)映射到"year"Rating(float64)映射到"rating",并使用omitempty,这样未评分的电影就不会显示评分字段InternalID(string)应使用"-"完全排除在 JSON 之外
创建函数
ToJSON(m Movie) string,将 Movie 转换为 JSON 字符串。再创建FromJSON(jsonStr string) Movie,将 JSON 字符串解析回 Movie 结构体。main.go:演示双向 JSON 转换。读取操作类型(
encode或decode)。对于
encode:逐行读取电影详情(title、director、year、rating)。创建一个 InternalID 为"internal-123"的 Movie,将其转换为 JSON 并打印结果。对于
decode:读取一个 JSON 字符串,将其转换为 Movie 结构体,并按以下格式打印电影详情:Title: [title] Director: [director] Year: [year] Rating: [rating]评分显示一位小数。如果评分为 0(JSON 中未提供),则打印
Rating: N/A。
输入内容如下:
- 第 1 行:操作类型(
encode或decode) - 对于 encode:title、director、year、rating(四行)
- 对于 decode:一个 JSON 字符串(一行)
例如,给定以下输入:
encode
Inception
Christopher Nolan
2010
8.8输出应为:
{"title":"Inception","director":"Christopher Nolan","year":2010,"rating":8.8}注意,由于使用了 "-" 标签,输出中不会出现 InternalID。
再比如,给定以下输入:
encode
The Matrix
Wachowskis
1999
0输出应为:
{"title":"The Matrix","director":"Wachowskis","year":1999}注意,由于评分为零且使用了 omitempty,rating 会被省略。
再比如,给定以下输入:
decode
{"title":"Interstellar","director":"Christopher Nolan","year":2014,"rating":8.6}输出应为:
Title: Interstellar
Director: Christopher Nolan
Year: 2014
Rating: 8.6再比如,给定以下输入:
decode
{"title":"Tenet","director":"Christopher Nolan","year":2020}输出应为:
Title: Tenet
Director: Christopher Nolan
Year: 2020
Rating: N/A亲手试试
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// 读取操作类型
operation, _ := reader.ReadString('\n')
operation = strings.TrimSpace(operation)
if operation == "encode" {
// 读取电影详情
title, _ := reader.ReadString('\n')
title = strings.TrimSpace(title)
director, _ := reader.ReadString('\n')
director = strings.TrimSpace(director)
yearStr, _ := reader.ReadString('\n')
yearStr = strings.TrimSpace(yearStr)
year, _ := strconv.Atoi(yearStr)
ratingStr, _ := reader.ReadString('\n')
ratingStr = strings.TrimSpace(ratingStr)
rating, _ := strconv.ParseFloat(ratingStr, 64)
// TODO:用读取的值创建 Movie 结构体
// 将 InternalID 设置为 "internal-123"
// 使用 ToJSON 转换为 JSON 并打印结果
} else if operation == "decode" {
// 读取 JSON 字符串
jsonStr, _ := reader.ReadString('\n')
jsonStr = strings.TrimSpace(jsonStr)
// TODO:使用 FromJSON 将 JSON 转换为 Movie
// 按要求的格式打印电影详情
// 使用 fmt.Sprintf("%.1f", rating) 格式化评分
// 如果 rating 为 0,则改为打印 "Rating: N/A"
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
11标准库与面向对象编程
io.Reader 与 io.Writersort.Interfacefmt.Stringer 接口使用 encoding/json 处理结构体http.Handler 接口回顾:REST API 模型自己练习: Go 在线编译器