c语言编程笔录

首页 >   > 笔记大全

笔记大全

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 解码器。