dongtu1789 2017-09-18 12:15
浏览 121
已采纳

在JSON golang中编码/解码多类型字段

I am trying to create a struct where a field can hold data of a few particular types, say int, string and a CustomType. I want to decode/encode this struct to/from JSON. How can we achieve this in go/golang?

For example, I have a struct for the following definition:

type MyData struct {
  Name  string                                    `json:"name"`
  Value int32                                     `json:"value"`
  Param <can be either int, string or CustomType> `json:"param"`
}

Where CustomType is

type CustomType struct {
  Custom bool `json:"custom"`
}

Let's say I need to unmarshal the following JSONs to the above struct MyData:

{
  "name": "Hello",
  "value": 32
  "param": "World"
}

And this one:

{
  "name": "Hello",
  "value": 32
  "param": 100
}

And this one also:

{
  "name": "Hello",
  "value": 32
  "param": {
     "custom": true
  }
}

How do I achieve this?

Can I define my own MarshalJSON and UnmarshalJSON on MyData and achieve this?

Or is there a way of defining a custom type, say IntOrStringOrCustom and define MyData as

type MyData struct {
  Name  string              `json:"name"`
  Value int32               `json:"value"`
  Param IntOrStringOrCustom `json:"param"`
}

and then define MarshalJSON and UnmarshalJSON on IntOrStringOrCustom?

I have also seen json.RawMessage. Can we use it somehow here?

Issue with using interface{} is that I will have to write the encoding/decoding logic everywhere, where I am trying to use this data. Or is there an elegant way of doing this with interface{}?

  • 写回答

1条回答 默认 最新

  • doushen9863 2017-09-18 12:24
    关注

    UPDATED. interface gets encoded and decoded to JSON well automatically. If you wish to control types, you may add special UnmarshalJSON and perform checks in it:

    type TheParam interface{}
    
    type MyData struct {
        Name  string   `json:"name"`
        Value int32    `json:"value"`
        Param TheParam `json:"param"`
    }
    
    type myData MyData
    
    func (m *MyData) UnmarshalJSON(b []byte) error {
        var mm myData
        if err := json.Unmarshal(b, &mm); err != nil {
            return err
        }
        switch mm.Param.(type) {
        case float64, string, map[string]interface{}:
            *m = MyData(mm)
            return nil
        default:
            return InvalidFieldTypeError{value: mm.Param}
        }
        return nil
    }
    

    Type InvalidFieldTypeError may be convenient to return such class of errors and can be defined as:

    type InvalidFieldTypeError struct {
        value interface{}
    }
    
    func (e InvalidFieldTypeError) Error() string {
        return fmt.Sprintf("Field type '%T' is not valid for MyData", e.value)
    }
    

    The whole example: https://play.golang.org/p/MuW6gwSAKi

    Also I'd like to recommend this article https://attilaolah.eu/2013/11/29/json-decoding-in-go/

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题