douhuireng4407 2019-05-03 08:14
浏览 63
已采纳

如何在结构类型中处理nil结构变量

I need to marshal/unmarshal json to struct in golang. Assume the struct is

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"`
}

The actors or payload maybe empty. The json maybe

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

or

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

If i follow the struct A design and try to marshal json with payload empty, i have to init as below

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{},
}

Which will result in below json with one empty payload struct

{
  "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":""
   }
}

Is there any way i can generate

"payload": ""

instead of blank payload struct? Or is there any other struct design for this kind of json format? BTW i cannot pass nil to Payload struct.

  • 写回答

2条回答 默认 最新

  • dongmou2389 2019-05-03 08:28
    关注

    The json.Marshaler interface can be implemented to customize JSON encoding, and the json.Unmarshaler interface for decoding (left as an exercise for the reader):

    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": ""
    //   }
    // }
    

    Try it on the playground: https://play.golang.org/p/9jhSWnKTnTf

    The ad-hoc _payload type is required to prevent recursion. If one would write return json.Marshal(p), the json package would call MarshalJSON again, because p is of type payload, and payload implements json.Marshaler.

    The _payload type has the same underlying type as payload but does not implement json.Marshaler (see Type definitions for details), so it is encoded using the standard rules of the json package; it produces exactly the same output that encoding a value of type payload would produce if payload didn't implement json.Marshaler.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?