Golang中JSON遇到的坑如何解决
更新时间:2023-10-04问题背景
在大多数 Web 服务应用程序中,JSON 是最受欢迎的数据交换格式。在使用 Go 编写代码进行处理 JSON 数据时,可能会遇到一些坑点。在这篇文章里,我将介绍在使用 Golang 处理 JSON 数据时可能遇到的问题,包括: 1. 解析 JSON 数据结构时空指针异常 2. 解析带有复杂数据类型的 JSON 数据 3. 解析带有日期格式的 JSON 数据 4. 处理 JSON 数据中的空白空指针异常的解决方案
当使用 Golang 解析 JSON 数据结构时,如果 JSON 编码出现空值(null),就会导致空指针异常。为了避免这种情况,我们需要在代码中添加判断 JSON 数据是否为空的代码。
type User struct { Name string `json:"name"` Age int `json:"age"` } func main() { jsonString := `{"name":"Tommy","age":null}` var user User json.Unmarshal([]byte(jsonString), &user) fmt.Printf("%#v", user) }
在上面的代码片段中,我们将 JSON 数据解析成结构体 User,其中 Age 值为 null。在启动代码时,我们会遇到空指针异常。
为了避免这种情况,我们可以使用 json.RawMessage,将原始数据转换为字节切片,并通过添加一个额外的 struct 来标记 JSON 输入的空值:
type NullInt64 struct { sql.NullInt64 } type User struct { Name string `json:"name"` Age NullInt64 `json:"age"` } func (ni *NullInt64) UnmarshalJSON(data []byte) error { if string(data) != "null" { return json.Unmarshal(data, &ni.NullInt64) } ni.Valid = false return nil } func main() { jsonString := `{"name":"Tommy","age":null}` var user User json.Unmarshal([]byte(jsonString), &user) fmt.Printf("%#v", user) }
处理带有复杂数据类型的 JSON 数据
在 Golang 中,json 解码器只能处理简单的数据类型。在处理复杂数据类型,比如数组、map 和嵌套结构体时,我们需要使用一些额外的技巧。
type User struct { Name string `json:"name"` Age int `json:"age"` Hobbies []string `json:"hobbies"` } func main() { jsonString := `{"name":"Tommy","age":30,"hobbies":["swimming","reading","coding"]}` var user User json.Unmarshal([]byte(jsonString), &user) fmt.Printf("%#v", user) }
在上面的代码片段中,我们定义了一些爱好的数组,来展示在 Golang 中如何处理复杂数据类型。
解析带有日期格式的 JSON 数据
在 Golang 中,时间按照 RFC3339 标准进行编码。如果您的 JSON 数据中包含其他格式的日期和时间,比如 ISO 标准,在处理时就会出现问题。为了解决这个问题,您需要定义一个用于将日期和时间去除它的字符串格式的函数。
type Message struct { Content string `json:"content"` Date time.Time `json:"date"` } func parseTime(strTime string) (time.Time, error) { var tm time.Time layout := "2006-01-02T15:04:05Z" tm, err := time.Parse(layout, strTime) if err != nil { return tm, err } return tm, nil } func (m *Message) UnmarshalJSON(data []byte) error { type Alias Message aux := struct { *Alias Date string `json:"date"` }{ Alias: (*Alias)(m), } if err := json.Unmarshal(data, &aux); err != nil { return err } tm, err := parseTime(aux.Date) if err != nil { return err } m.Date = tm return nil } func main() { jsonString := `{"content":"Hello, world!","date":"2021-04-15T18:50:51+08:00"}` var m Message json.Unmarshal([]byte(jsonString), &m) }
处理 JSON 数据中的空白
在 Golang 中,json 解码器默认忽略空白。如果您希望保留 JSON 数据中的空白,可以使用 json.Decoder,并且为其设置 UseNumber 选项,以避免将数字类型解析为浮点数。
type User struct { Name string `json:"name"` Age int `json:"age"` } func main() { jsonString := `{ "name": "Tommy", "age": 30, }` var user User var decoder = json.NewDecoder(strings.NewReader(jsonString)) decoder.UseNumber() decoder.Decode(&user) fmt.Printf("%#v", user) }
总结
在 Golang 中,JSON 解码器提供了一种简单的方法来处理和解析 JSON 数据。但是,只有当您理解 JSON 数据的结构和编码规则时,才能充分利用这个功能。了解在上面提到的几个问题的解决方案,可以使您更加熟练地使用 Golang 的 JSON 解码器。