JSON 持久化层
本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 102 课,共 107 课。
挑战
简单让我们的图书馆管理系统支持数据持久化吧!你将实现一个 JSON 持久化层,把图书馆的数据转换为 JSON 格式以便保存,并能从 JSON 字符串中加载数据。这对于任何需要在不同会话之间保留数据的实际应用都至关重要。
你将把代码分到 5 个文件中:
book.go:定义带有 JSON 结构体标签的Book结构体,以控制序列化。每个字段都应有对应的 JSON 标签:id、title、author、isbn和available。还要包含NewBook构造函数。user.go:定义带有 JSON 结构体标签的User结构体,标签分别为id、name、email和borrowed_books。还要包含NewUser构造函数。data.go:创建一个LibraryData结构体,作为 JSON 序列化的数据传输对象。它应有两个字段:Books(Book 指针切片)和Users(User 指针切片),每个字段都要有合适的 JSON 标签(books和users)。library.go:定义用于存放图书和用户映射的Library结构体。新增两个方法:ToJSON():使用json.MarshalIndent将图书馆的数据转换为格式化的 JSON 字符串,并使用两个空格缩进。该方法应从映射中收集所有图书和用户,放入LibraryData结构体,然后进行序列化。FromJSON(jsonStr string):接收一个 JSON 字符串,将其反序列化到LibraryData结构体中,并用加载的图书和用户填充图书馆的映射。
main.go:通过创建图书馆并将其转换为 JSON,演示持久化层的用法。读取图书数量,然后依次读取每本图书的 ID、标题、作者和 ISBN。接着读取用户数量,然后依次读取每位用户的 ID、姓名和电子邮箱。填充图书馆后,调用
ToJSON()并打印生成的 JSON 字符串。
输入将按以下格式提供:
- 图书数量,然后是每本图书的 ID、标题、作者和 ISBN(每项各占一行)
- 用户数量,然后是每位用户的 ID、姓名和电子邮箱(每项各占一行)
例如,输入:
2
B001
The Go Programming Language
Alan Donovan
978-0134190440
B002
Clean Code
Robert Martin
978-0132350884
1
U001
Alice Smith
alice@library.com输出应为:
{
"books": [
{
"id": "B001",
"title": "The Go Programming Language",
"author": "Alan Donovan",
"isbn": "978-0134190440",
"available": true
},
{
"id": "B002",
"title": "Clean Code",
"author": "Robert Martin",
"isbn": "978-0132350884",
"available": true
}
],
"users": [
{
"id": "U001",
"name": "Alice Smith",
"email": "alice@library.com",
"borrowed_books": []
}
]
}再例如,输入:
1
B100
Design Patterns
Gang of Four
978-0201633610
0输出应为:
{
"books": [
{
"id": "B100",
"title": "Design Patterns",
"author": "Gang of Four",
"isbn": "978-0201633610",
"available": true
}
],
"users": []
}重要:遍历映射以构建切片时,应按以下顺序添加图书:B001、B002 等(按 ID 的字母顺序排序),用户也要按相同方式排序。这样可以确保 JSON 输出一致。你可以先对映射的键使用 sort.Strings 排序,再进行遍历。
LibraryData 结构体连接了基于映射的存储方式与 JSON 基于数组的格式。这种传输对象模式常用于序列化复杂的数据结构!
亲手试试
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// 创建一个新库
library := NewLibrary()
// 读取图书数量
numBooksStr, _ := reader.ReadString('\n')
numBooks, _ := strconv.Atoi(strings.TrimSpace(numBooksStr))
// TODO: 读取每本书的详细信息(ID、书名、作者、ISBN)
// 并将它们添加到库中
for i := 0; i < numBooks; i++ {
// TODO: 读取图书 ID
// TODO: 读取书名
// TODO: 读取图书作者
// TODO: 读取图书 ISBN
// TODO: 创建图书并添加到库中
}
// 读取用户数量
numUsersStr, _ := reader.ReadString('\n')
numUsers, _ := strconv.Atoi(strings.TrimSpace(numUsersStr))
// TODO: 读取每位用户的详细信息(ID、姓名、邮箱)
// 并将它们添加到库中
for i := 0; i < numUsers; i++ {
// TODO: 读取用户 ID
// TODO:读取用户姓名
// TODO:读取用户邮箱
// TODO:创建用户并添加到库中
}
// TODO:将库转换为 JSON 并输出
fmt.Println(library.ToJSON())
}
面向对象编程中的所有课
自己练习: Go 在线编译器