问题
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:
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/
来源:https://stackoverflow.com/questions/46279048/encoding-decoding-multi-type-fields-in-json-golang