【问题标题】:How to handle nil struct variable in struct type如何处理结构类型中的零结构变量
【发布时间】:2019-09-21 18:17:35
【问题描述】:

我需要编组/解组 json 以在 golang 中构建结构。假设结构是

type A struct {
  Id string `json:"id"`
  Version string `json:"version"`
  Actors []actor `json:"actors`
  Payload struct {
     Name string `json:"name"`
     Number string `json:"number"`
  }
}
type payload struct {
    Name string `json:"name"`
    Number string `json:"number"`
}
type actor struct {
    Id   string `json:"id"`
    Type string `json:"type"`
    Role string `json:"role"`
}

演员或有效载荷可能是空的。 json可能

{
  "id": "78a07cea-be2b-499c-b82b-e4f510260484",
  "version": "1.0.0",
  "actors": [
    {
      "id": "1234567",
      "type": "XXX",
      "role": "111"
    },
    {
      "id": "7654321",
      "type": "YYY",
      "role": "222"
    }
  ],
  "payload": ""
}

{
  "id": "78a07cea-be2b-499c-b82b-e4f510260484",
  "version": "1.0.0",
  "actors": [],
  "payload": {
       "name": "XXXX",
       "number": "1234567"
   }
}

如果我遵循 struct A 设计并尝试在有效负载为空的情况下编组 json,我必须按如下方式初始化

a := A{
  Id: "78a07cea-be2b-499c-b82b-e4f510260484",
  Version: "1.0.0",
  Actors: []actor{
    actor{
      Id: "1234567",
      Type: "XXX",
      Role: "111",
    },
    actor{
      Id: "7654321",
      Type: "YYY",
      Role: "222",
    },
  },
  Payload: payload{},
}

这将导致下面的 json 带有一个空的有效负载结构

{
  "id": "78a07cea-be2b-499c-b82b-e4f510260484",
  "version": "1.0.0",
  "actors": [
    {
      "id": "1234567",
      "type": "XXX",
      "role": "111"
    },
    {
      "id": "7654321",
      "type": "YYY",
      "role": "222"
    }
  ],
  "payload": {
     "name":"",
     "number":""
   }
}

有什么办法可以生成

“有效载荷”:“”

而不是空白有效载荷结构?或者这种 json 格式还有其他结构设计吗?顺便说一句,我不能将 nil 传递给 Payload 结构。

【问题讨论】:

    标签: go struct


    【解决方案1】:

    json.Marshaler interface 可以实现自定义 JSON 编码,json.Unmarshaler interface 用于解码(留给读者练习):

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    type A struct {
        Payload payload
    }
    
    type payload struct {
        Name   string `json:"name"`
        Number string `json:"number"`
    }
    
    func (p payload) MarshalJSON() ([]byte, error) {
        if p.Name == "" && p.Number == "" {
            return []byte(`""`), nil
        }
    
        type _payload payload // prevent recursion
        return json.Marshal(_payload(p))
    }
    
    func main() {
        var a A
        b, _ := json.MarshalIndent(a, "", "  ")
        fmt.Println(string(b))
    
        a.Payload.Name = "foo"
        b, _ = json.MarshalIndent(a, "", "  ")
        fmt.Println(string(b))
    }
    
    // Output:
    // {
    //   "Payload": ""
    // }
    // {
    //   "Payload": {
    //     "name": "foo",
    //     "number": ""
    //   }
    // }
    

    在操场上试试看:https://play.golang.org/p/9jhSWnKTnTf

    需要特殊的_payload 类型来防止递归。如果写return json.Marshal(p),json 包会再次调用MarshalJSON,因为p 的类型是payload,而payload 实现了json.Marshaler。

    _payload 类型与payload 具有相同的底层类型,但 实现了 json.Marshaler(详见Type definitions),因此使用标准规则对其进行编码json包;如果 payload 没有实现 json.Marshaler,它会产生与编码 payload 类型的值完全相同的输出。

    【讨论】:

    • @Peter 你能解释一下type _payload payload // prevent recursion这里发生了什么或者我应该读什么来了解这个吗? :)
    • @Peter 明白了。非常感谢:)
    【解决方案2】:

    检查使用带有 json 结构标记的 omitempty 是否有帮助。我认为这将导致"payload": {} 而不是"payload": ""

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-17
      • 2019-04-26
      • 2022-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多