main.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. )
  8. // 字段需要导出(大写开头)才能由 encoding/json 读写。
  9. // 反引号中的内容是结构体标签,不是字段的值。
  10. type StudyRecord struct {
  11. Title string `json:"title"`
  12. Minutes int `json:"minutes"`
  13. Finished bool `json:"finished"`
  14. Tags []string `json:"tags"`
  15. Note string `json:"note,omitempty"`
  16. }
  17. // encodeRecord 将结构体转换为缩进后的 JSON 字节。
  18. func encodeRecord(record StudyRecord) ([]byte, error) {
  19. return json.MarshalIndent(record, "", " ")
  20. }
  21. // decodeRecord 将 JSON 字节解析到新结构体。
  22. // 本例只检查 JSON 语法和字段类型,不验证学习时长等业务规则。
  23. func decodeRecord(data []byte) (StudyRecord, error) {
  24. var record StudyRecord
  25. if err := json.Unmarshal(data, &record); err != nil {
  26. return StudyRecord{}, err
  27. }
  28. return record, nil
  29. }
  30. func run() error {
  31. record := StudyRecord{
  32. Title: "学习 Go JSON",
  33. Minutes: 30,
  34. Finished: true,
  35. Tags: []string{"Go", "JSON"},
  36. // Note 为空字符串,会因 omitempty 在编码时省略。
  37. }
  38. // 1. 编码:Go 值 -> JSON 字节。
  39. data, err := encodeRecord(record)
  40. if err != nil {
  41. return fmt.Errorf("编码记录:%w", err)
  42. }
  43. fmt.Println("=== 编码为 JSON ===")
  44. fmt.Println(string(data))
  45. // 2. 每次创建独立临时目录,不覆盖已有文件;运行结束保留供查看。
  46. directory, err := os.MkdirTemp("", "go-lesson18-")
  47. if err != nil {
  48. return fmt.Errorf("创建临时目录:%w", err)
  49. }
  50. path := filepath.Join(directory, "record.json")
  51. // WriteFile 会覆盖已有文件;此处使用新建目录中的文件。
  52. if err := os.WriteFile(path, data, 0600); err != nil {
  53. return fmt.Errorf("保存记录:%w", err)
  54. }
  55. fmt.Println("记录文件(运行后保留):", path)
  56. // 3. 读取文件,解码:JSON 字节 -> Go 值。
  57. saved, err := os.ReadFile(path)
  58. if err != nil {
  59. return fmt.Errorf("读取记录:%w", err)
  60. }
  61. decoded, err := decodeRecord(saved)
  62. if err != nil {
  63. return fmt.Errorf("解码记录:%w", err)
  64. }
  65. fmt.Println("\n=== 读取并解码 ===")
  66. fmt.Printf("标题:%s,时长:%d 分钟,完成:%t,标签:%v\n", decoded.Title, decoded.Minutes, decoded.Finished, decoded.Tags)
  67. // 4. 非法 JSON 会返回错误;这里只演示,不让它中断整个程序。
  68. _, err = decodeRecord([]byte(`{"minutes": "不是数字"}`))
  69. if err != nil {
  70. fmt.Println("\n=== 错误示例 ===")
  71. fmt.Println("字段类型不匹配,解码失败")
  72. }
  73. return nil
  74. }
  75. func main() {
  76. if err := run(); err != nil {
  77. fmt.Fprintln(os.Stderr, "程序失败:", err)
  78. os.Exit(1)
  79. }
  80. }