| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- package main
- import (
- "encoding/json"
- "fmt"
- "os"
- "path/filepath"
- )
- // 字段需要导出(大写开头)才能由 encoding/json 读写。
- // 反引号中的内容是结构体标签,不是字段的值。
- type StudyRecord struct {
- Title string `json:"title"`
- Minutes int `json:"minutes"`
- Finished bool `json:"finished"`
- Tags []string `json:"tags"`
- Note string `json:"note,omitempty"`
- }
- // encodeRecord 将结构体转换为缩进后的 JSON 字节。
- func encodeRecord(record StudyRecord) ([]byte, error) {
- return json.MarshalIndent(record, "", " ")
- }
- // decodeRecord 将 JSON 字节解析到新结构体。
- // 本例只检查 JSON 语法和字段类型,不验证学习时长等业务规则。
- func decodeRecord(data []byte) (StudyRecord, error) {
- var record StudyRecord
- if err := json.Unmarshal(data, &record); err != nil {
- return StudyRecord{}, err
- }
- return record, nil
- }
- func run() error {
- record := StudyRecord{
- Title: "学习 Go JSON",
- Minutes: 30,
- Finished: true,
- Tags: []string{"Go", "JSON"},
- // Note 为空字符串,会因 omitempty 在编码时省略。
- }
- // 1. 编码:Go 值 -> JSON 字节。
- data, err := encodeRecord(record)
- if err != nil {
- return fmt.Errorf("编码记录:%w", err)
- }
- fmt.Println("=== 编码为 JSON ===")
- fmt.Println(string(data))
- // 2. 每次创建独立临时目录,不覆盖已有文件;运行结束保留供查看。
- directory, err := os.MkdirTemp("", "go-lesson18-")
- if err != nil {
- return fmt.Errorf("创建临时目录:%w", err)
- }
- path := filepath.Join(directory, "record.json")
- // WriteFile 会覆盖已有文件;此处使用新建目录中的文件。
- if err := os.WriteFile(path, data, 0600); err != nil {
- return fmt.Errorf("保存记录:%w", err)
- }
- fmt.Println("记录文件(运行后保留):", path)
- // 3. 读取文件,解码:JSON 字节 -> Go 值。
- saved, err := os.ReadFile(path)
- if err != nil {
- return fmt.Errorf("读取记录:%w", err)
- }
- decoded, err := decodeRecord(saved)
- if err != nil {
- return fmt.Errorf("解码记录:%w", err)
- }
- fmt.Println("\n=== 读取并解码 ===")
- fmt.Printf("标题:%s,时长:%d 分钟,完成:%t,标签:%v\n", decoded.Title, decoded.Minutes, decoded.Finished, decoded.Tags)
- // 4. 非法 JSON 会返回错误;这里只演示,不让它中断整个程序。
- _, err = decodeRecord([]byte(`{"minutes": "不是数字"}`))
- if err != nil {
- fmt.Println("\n=== 错误示例 ===")
- fmt.Println("字段类型不匹配,解码失败")
- }
- return nil
- }
- func main() {
- if err := run(); err != nil {
- fmt.Fprintln(os.Stderr, "程序失败:", err)
- os.Exit(1)
- }
- }
|