Golang中如何处理空值(nulls)问题

Golang中如何处理空值(nulls)问题 你好, 我正在寻找一种方法来保留从 REST API 服务器以 JSON 格式发送的空值。目前,我使用结构体和反序列化,但这会将空值转换为零。

有人有快速的代码示例或关于这个问题的好视频链接吗?我尝试过使用指针,但我不理解它如何有帮助,我仍然看到零值。

func main() {
    fmt.Println("hello world")
}
4 回复
type foo struct {
  Foo *int `json:"foo"`
}

更多关于Golang中如何处理空值(nulls)问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Go语言的一个优点是len()是一个静态函数。在读取长度甚至遍历切片之前,你不需要对切片进行空值检查。对于大多数用途来说,一个nil切片的行为就像一个长度为0的切片。

当然,对于所有其他基本类型、结构体和映射,你的观点是正确的。

你好 Sivan,

正如 NobbZ 所说,你可以使用一个指针来表明数据可能不存在。

type Foo struct {
  Bar *string `json:"bar"`
}

请记住,如果你使用一个值并且它可能为空,在使用该值之前需要进行空值检查,否则你会遇到 panic: runtime error: invalid memory address or nil pointer dereference 错误。你可以像这样处理:

var foo Foo

//... 反序列化到 Foo

if foo.Bar != nil {
// 在这里使用 len() 是安全的
fmt.Println(len(*foo.Bar))
}

你可能还想了解一下 omitemptyomitzero 这两个 JSON 标签,它们可以用来清理你的 JSON 输出。你可以搜索一下相关资料(omitzero 是在 Go 1.24 中引入的,所以它比较新,你可能找不到太多关于它的资源)。

在Golang中处理JSON空值的关键是使用指针类型。指针可以区分"未设置"、“null"和"零值”。以下是具体实现:

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    ID        int     `json:"id"`
    Name      *string `json:"name"`      // 使用指针
    Age       *int    `json:"age"`       // 使用指针
    IsActive  *bool   `json:"isActive"`  // 使用指针
}

func main() {
    // JSON数据包含null值
    jsonData := `{
        "id": 1,
        "name": null,
        "age": null,
        "isActive": null
    }`

    var user User
    err := json.Unmarshal([]byte(jsonData), &user)
    if err != nil {
        panic(err)
    }

    // 检查各个字段
    fmt.Printf("ID: %d\n", user.ID)  // 1
    
    if user.Name == nil {
        fmt.Println("Name: null")  // 输出: Name: null
    } else {
        fmt.Printf("Name: %s\n", *user.Name)
    }
    
    if user.Age == nil {
        fmt.Println("Age: null")  // 输出: Age: null
    } else {
        fmt.Printf("Age: %d\n", *user.Age)
    }
    
    if user.IsActive == nil {
        fmt.Println("IsActive: null")  // 输出: IsActive: null
    } else {
        fmt.Printf("IsActive: %v\n", *user.IsActive)
    }
}

对于更复杂的场景,可以使用json.RawMessage

package main

import (
    "encoding/json"
    "fmt"
)

type FlexibleUser struct {
    ID       int             `json:"id"`
    Metadata json.RawMessage `json:"metadata"` // 保留原始JSON
}

func main() {
    jsonData := `{
        "id": 1,
        "metadata": null
    }`

    var user FlexibleUser
    err := json.Unmarshal([]byte(jsonData), &user)
    if err != nil {
        panic(err)
    }

    fmt.Printf("ID: %d\n", user.ID)
    fmt.Printf("Metadata (raw): %s\n", string(user.Metadata)) // 输出: null
    
    // 检查是否为null
    if string(user.Metadata) == "null" {
        fmt.Println("Metadata is null")
    }
}

使用sql.Null类型处理数据库空值:

package main

import (
    "database/sql"
    "encoding/json"
    "fmt"
)

type Product struct {
    ID    int            `json:"id"`
    Price sql.NullFloat64 `json:"price"`
    Name  sql.NullString `json:"name"`
}

func (p Product) MarshalJSON() ([]byte, error) {
    type Alias Product
    aux := &struct {
        *Alias
        Price interface{} `json:"price"`
        Name  interface{} `json:"name"`
    }{
        Alias: (*Alias)(&p),
    }
    
    if p.Price.Valid {
        aux.Price = p.Price.Float64
    } else {
        aux.Price = nil
    }
    
    if p.Name.Valid {
        aux.Name = p.Name.String
    } else {
        aux.Name = nil
    }
    
    return json.Marshal(aux)
}

func main() {
    product := Product{
        ID:    1,
        Price: sql.NullFloat64{Valid: false}, // null
        Name:  sql.NullString{String: "Laptop", Valid: true},
    }
    
    data, _ := json.Marshal(product)
    fmt.Println(string(data)) // {"id":1,"price":null,"name":"Laptop"}
}

这些方法可以准确区分JSON中的null值和零值。

回到顶部