我知道这可能是一个常见的问题,但请恕我直言...

我有一个 struct ,其中一个字段类型与另一个 struct 的字段类型相同:

type Developer struct {
    Name       string `json:"name,omitempty"`
    ProjectRef *Ref   `json:"project,omitempty"`
}

type Ref struct {
    ID string `json:"id,omitempty"`
}

In my implementation I cannot guarantee if there is or isn't going to be a ProjectRef for a Developer. If I create a Ref with a null ID, i.e. an empty string, then this field is omitted from the Ref, however, even though my Ref has no fields at this point, why is it not omitted from being empty?

我想克服这个问题的一种方法是使用一堆条件语句,但我不想让自己这么做,因为我有很多情况下需要这种功能.

完整演示代码:

package main

import (
    "encoding/json"
    "fmt"
)

type Developer struct {
    Name       string `json:"name,omitempty"`
    ProjectRef *Ref   `json:"project,omitempty"`
}

type Ref struct {
    ID string `json:"id,omitempty"`
}

func main() {
    developer := &Developer{
        Name:       "Charlie",
        ProjectRef: &Ref{ID: ""},
    }

    jsonBytes, err := json.Marshal(developer)
    if err != nil {
        panic(err)
    }

    fmt.Println(string(jsonBytes))
// {"name":"Charlie","project":{}}
}

链接到操场:https://go.dev/play/p/D2edbrACXY2

Thank you in advance

推荐答案

struct 是编组的,即使它们的所有字段都包含zero values.

一种方法是离开Developer.ProjectRef字段nil,然后删除omitempty属性.这样,它将被封送到JSON null值中:

type Developer struct {
    Name       string `json:"name,omitempty"`
    ProjectRef *Ref   `json:"project"`
}

测试它:

developer := &Developer{
    Name:       "Charlie",
}

jsonBytes, err := json.Marshal(developer)
if err != nil {
    panic(err)
}
fmt.Println(string(jsonBytes))

developer.ProjectRef = &Ref{ID: "abc"}

jsonBytes, err = json.Marshal(developer)
if err != nil {
    panic(err)
}
fmt.Println(string(jsonBytes))

Output (try it on the Go Playground):

{"name":"Charlie","project":null}
{"name":"Charlie","project":{"id":"abc"}}

如果您总是希望Developer.ProjectRef是非nil指针,那么为Ref编写一个自定义的JSON marshaler,如果ID为空,它可以封送JSON null的值:

func (r *Ref) MarshalJSON() ([]byte, error) {
    if r.ID == "" {
        return []byte("null"), nil
    }
    type ref2 Ref
    return json.Marshal((*ref2)(r))
}

测试它:

developer := &Developer{
    Name:       "Charlie",
    ProjectRef: &Ref{ID: ""},
}

jsonBytes, err := json.Marshal(developer)
if err != nil {
    panic(err)
}
fmt.Println(string(jsonBytes))

developer.ProjectRef.ID = "abc"

jsonBytes, err = json.Marshal(developer)
if err != nil {
    panic(err)
}
fmt.Println(string(jsonBytes))

Output (try it on the Go Playground):

{"name":"Charlie","project":null}
{"name":"Charlie","project":{"id":"abc"}}

Json相关问答推荐

两种情况下过滤的JOLT规范

如何在PowerShell中访问嵌套的JSON字段

JSON API返回多个数组,需要帮助拼合数据以存储在SQL Server数据库表中

需要有关在Ffltter应用程序中解码JSON的帮助;未处理的异常:类型不是类型转换中类型的子类型

规范化JSON数据

当并非所有子对象都有 Select 器字段时 Select

Oracle JSON 查询中的动态列列表

根据值过滤输入的JSON并使用它准备预期的输出

条件性构建/修改嵌套对象数组

在 NX 工作区中跨多个应用共享 ngx-translate 翻译文件

使用 Groovy 将 XML 转换为 JSON

如何在不使用 Newtonsoft.JSON 的情况下序列化/反序列化

如何从条带订阅响应对象中正确获取 struct 项?

流导入错误:重新上传时不存在布局释放 UUID

我无法在 Go - Gin 中解析日期/时间

如何在 Go 中生成带有排序键的 JSON?

一起使用 Argparse 和 Json

IE中Json响应下载(7~10)

如何创建 JSON 对象 Node.js

如何使用 Gson 解码具有未知字段的 JSON?