You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言JSON序列化时如何显示空对象而非空结构体或nil

解决Go中结构体指针序列化为JSON空对象{}的问题

这个问题我之前也碰到过,Go标准库的json.Marshal默认行为确实会让人有点头疼——未初始化的指针输出null,初始化的空结构体又会把零值字段都打出来。不过有两种靠谱的解决办法,你可以根据自己的需求选:

方案一:给结构体字段加omitempty标签(最简单)

这是最直接的办法,只要给Person结构体的每个字段加上json:"字段名,omitempty"标签,当字段是零值时就会被序列化器忽略,最终空结构体就会变成{}。

示例代码:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "time"
)

type Person struct {
    Name string `json:"name,omitempty"` // 加omitempty标签
    Age  int    `json:"age,omitempty"`  // 加omitempty标签
}

type Response struct {
    Data struct {
        Person      *Person   `json:"person"`
        CreatedDate time.Time `json:"created_date"`
    } `json:"data"`
}

func main() {
    resp := Response{
        Data: struct {
            Person      *Person   `json:"person"`
            CreatedDate time.Time `json:"created_date"`
        }{
            Person:      &Person{}, // 初始化空结构体
            CreatedDate: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC),
        },
    }

    data, err := json.Marshal(resp)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(data))
    // 输出:{"data":{"person":{},"created_date":"2009-11-10T23:00:00Z"}}
}

这个方案的好处是代码改动极小,适合大多数场景。但如果你有需求要保留某些零值字段(比如Age为0是有意义的,不能忽略),那可以看第二种方案。

方案二:自定义JSON序列化逻辑

通过让*Person实现json.Marshaler接口,我们可以完全控制它的序列化行为——不管指针是nil还是指向零值结构体,都输出{},有非零值时再正常序列化。

示例代码:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "time"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

// 给*Person实现MarshalJSON方法
func (p *Person) MarshalJSON() ([]byte, error) {
    // 情况1:指针为nil,直接返回{}
    if p == nil {
        return []byte("{}"), nil
    }
    // 情况2:结构体是零值,返回{}
    if p.Name == "" && p.Age == 0 {
        return []byte("{}"), nil
    }
    // 情况3:有非零值,正常序列化(用Alias避免递归调用)
    type Alias Person
    return json.Marshal((*Alias)(p))
}

type Response struct {
    Data struct {
        Person      *Person   `json:"person"`
        CreatedDate time.Time `json:"created_date"`
    } `json:"data"`
}

func main() {
    // 测试空结构体指针
    resp1 := Response{
        Data: struct {
            Person      *Person   `json:"person"`
            CreatedDate time.Time `json:"created_date"`
        }{
            Person:      &Person{},
            CreatedDate: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC),
        },
    }
    data1, _ := json.Marshal(resp1)
    fmt.Println(string(data1))
    // 输出:{"data":{"person":{},"created_date":"2009-11-10T23:00:00Z"}}

    // 测试nil指针
    resp2 := Response{
        Data: struct {
            Person      *Person   `json:"person"`
            CreatedDate time.Time `json:"created_date"`
        }{
            Person:      nil,
            CreatedDate: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC),
        },
    }
    data2, _ := json.Marshal(resp2)
    fmt.Println(string(data2))
    // 输出:{"data":{"person":{},"created_date":"2009-11-10T23:00:00Z"}}

    // 测试有值的结构体
    resp3 := Response{
        Data: struct {
            Person      *Person   `json:"person"`
            CreatedDate time.Time `json:"created_date"`
        }{
            Person:      &Person{Name: "Alice", Age: 30},
            CreatedDate: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC),
        },
    }
    data3, _ := json.Marshal(resp3)
    fmt.Println(string(data3))
    // 输出:{"data":{"person":{"name":"Alice","age":30},"created_date":"2009-11-10T23:00:00Z"}}
}

这个方案更灵活,能区分“零值结构体”和“有意义的零值”场景,适合复杂的业务需求。

内容的提问来源于stack exchange,提问作者tama

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:24:37