首页 > 解决方案 > 如何处理结构类型中的零结构变量

问题描述

我需要编组/解组 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 结构。

标签: gostruct

解决方案


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

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

需要ad-hoc_payload类型来防止递归。如果有人写return json.Marshal(p),json 包会MarshalJSON再次调用,因为 p 是类型payload,并且payload实现了 json.Marshaler。

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


推荐阅读