
Go 中 json.Marshal 返回空对象 {} 的根本原因是结构体字段未导出(首字母小写),导致反射无法访问;只需将字段改为大写首字母并同步更新数据库扫描逻辑,即可生成完整 JSON。
go 中 `json.marshal` 返回空对象 `{}` 的根本原因是结构体字段未导出(首字母小写),导致反射无法访问;只需将字段改为大写首字母并同步更新数据库扫描逻辑,即可生成完整 json。
在 Go 语言中,encoding/json 包依赖 reflect 包对数据进行序列化。而 Go 的反射机制仅能访问导出(exported)字段——即字段名必须以大写字母开头。若结构体字段全部为小写(如 isbn string),json.Marshal 将忽略所有字段,最终输出空 JSON 对象 {},即使结构体实例本身包含有效数据。
✅ 正确做法:导出字段 + 显式 JSON 标签(推荐)
type Book struct {
ISBN string `json:"isbn"` // 导出字段 + 自定义小写键名
Title string `json:"title"`
Author string `json:"author"`
Price float32 `json:"price"`
}同时,务必同步更新 rows.Scan 的参数顺序与字段名:
for rows.Next() {
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.Marshal(bks) 将输出标准、可读的 JSON:
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
[
{"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}
]⚠️ 注意事项
- 字段可见性是前提:json:"xxx" 标签仅作用于已导出字段;对 isbn string 这类未导出字段加 tag 完全无效。
-
零值字段处理:如需在 JSON 中省略空值(如 ""、0、nil),可在 tag 中添加 ,omitempty,例如:
Title string `json:"title,omitempty"`
- 数据库列名不匹配? 若 PostgreSQL 字段名为 book_title,仍可用 json:"title" 控制输出键名,不影响扫描(rows.Scan 仅依赖参数顺序,与 JSON key 无关)。
- 避免指针陷阱:bk := new(Book) 创建的是指针,但 *bk 解引用后赋值给切片时,确保所有字段均已正确扫描,否则可能引入零值。
? 验证技巧
可在 getBooksFromDB 中加入调试日志:
log.Printf("marshaling %d books", len(b))
data, _ := json.MarshalIndent(b, "", " ") // 格式化输出便于排查
log.Println(string(data))总结:Go 的 JSON 序列化严格遵循“导出即可见”原则。小写字段 → 不导出 → 反射不可见 → JSON 空对象。统一使用大写首字母字段 + json:"xxx" 标签,是最简洁、可靠且符合 Go 惯例的解决方案。

















