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 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化
  • ¥15 Mirare PLUS 进行密钥认证?(详解)
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥20 想用ollama做一个自己的AI数据库
  • ¥15 关于qualoth编辑及缝合服装领子的问题解决方案探寻
  • ¥15 请问怎么才能复现这样的图呀