
Go 的 json.Marshal 仅序列化结构体中首字母大写的可导出字段;若字段全为小写(如 isbn string),反射无法访问,导致输出为空 JSON {}。解决方法是将字段名改为大写并同步更新数据库扫描逻辑。
go 的 `json.marshal` 仅序列化结构体中首字母大写的**可导出字段**;若字段全为小写(如 `isbn string`),反射无法访问,导致输出为空 json `{}`。解决方法是将字段名改为大写并同步更新数据库扫描逻辑。
在 Go 语言中,encoding/json 包通过反射机制实现结构体到 JSON 的自动转换。但其有一个关键前提:只有可导出(exported)字段——即首字母大写的字段——才会被 json.Marshal 识别并编码。而你在 Book 结构体中定义的字段全部为小写(isbn, title, author, price),属于不可导出的私有字段,json 包完全无法访问它们,因此无论结构体实际包含多少数据,json.Marshal(b) 始终返回空对象 {}(单个对象)或空数组 [{}](切片中含零值结构体),这正是你截图中看到 "{}" 的根本原因。
✅ 正确做法:修改结构体字段为可导出,并配合 json tag 精确控制键名
type Book struct {
Isbn string `json:"isbn"`
Title string `json:"title"`
Author string `json:"author"`
Price float32 `json:"price"`
}同时,务必同步更新 rows.Scan 中的字段引用:
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
bk := new(Book)
err := rows.Scan(&bk.Isbn, &bk.Title, &bk.Author, &bk.Price) // 注意首字母大写!
if err != nil {
log.Fatal(err)
}
bks = append(bks, *bk)? 进阶提示:
- 若希望 JSON 键名保持小写(如 "isbn"),必须显式使用 json:"isbn" tag;否则默认会使用大写字段名(如 "Isbn" → "Isbn")。
- json:"-" 可忽略字段;json:",omitempty" 可在字段为零值(空字符串、0、nil 等)时跳过该键。
- 所有字段类型也需可导出(如嵌套结构体字段),否则嵌套部分仍为空。
⚠️ 注意事项:
- 不要混淆「字段可导出性」与「JSON 键名大小写」:前者决定是否参与序列化,后者由 tag 控制;
- 数据库扫描(Scan)和 JSON 序列化是两个独立环节,二者字段名必须严格一致(大小写+数量),否则会 panic 或静默失败;
- 使用 sql.NullString 等类型处理可能为 NULL 的数据库字段,避免扫描时类型不匹配错误。
总结:Go 的 JSON 生态严格遵循语言可见性规则。让字段可导出是序列化的前提,用 struct tag 定制键名是专业实践的标准范式。 修改后,你的 /db 接口将正确输出类似:
[
{"isbn":"978-1503261969","title":"Emma","author":"Jane Austen","price":9.44},
{"isbn":"978-1505255607","title":"The Time Machine","author":"H. G. Wells","price":5.99}
]

















