在 Go 中,JSON 的导出标准是通过 encoding/json 包实现的。只有可导出的(大写字母开头)结构体字段可以被序列化。为了控制名称和处理,使用结构体标签:
type User struct { ID int `json:"id"` Name string `json:"name,omitempty"` Age int `json:"age,string"` }
omitempty 在值为零时排除字段;string 将值作为字符串进行序列化,即使它是数字。user := User{ID: 1, Name: "Олег"} b, _ := json.Marshal(user) fmt.Println(string(b)) // {"id":1,"name":"Олег","age":"0"}
var u User json.Unmarshal([]byte('{"id":2,"name":"Иван"}'), &u)
在 JSON 序列化时,结构体中不可导出(小写字母开头)字段是如何序列化的?
正确答案: 它们会被忽略,只有可导出的(大写字母开头)字段参与序列化。这常常会意外破坏 API:
type Foo struct { bar int // 不会被序列化! }
故事
后端产生了不完整的 JSON 对象,因为部分需要的字段未导出(小写字母开头)。花了几天才弄清楚客户为什么看不到这些字段。
故事
API 的响应字段包含了 omitempty 结构,但有时会收到空值,因为切片的零值是 nil,而不是空切片。客户获得了 null 而不是空数组 [],在解析时崩溃。
故事
项目中通过 map[字符串]接口 向结构体中添加动态字段,但忘记实现自定义 UnmarshalJSON,导致部分数据在没有错误的情况下被“丢失”。客户的数据被丢失并通过备份手动恢复。