Encoding/Decoding JSON golang 中的多类型字段
Encoding/Decoding multi-type fields in JSON golang
我正在尝试创建一个结构,其中一个字段可以保存一些特定类型的数据,例如 int
、string
和 CustomType
。我想 decode/encode 这个结构 to/from JSON。我们如何才能在 go/golang 中实现这一目标?
例如,我有一个用于以下定义的结构:
type MyData struct {
Name string `json:"name"`
Value int32 `json:"value"`
Param <can be either int, string or CustomType> `json:"param"`
}
其中 CustomType
是
type CustomType struct {
Custom bool `json:"custom"`
}
假设我需要将以下 JSON 解组到上面的结构 MyData
:
{
"name": "Hello",
"value": 32
"param": "World"
}
还有这个:
{
"name": "Hello",
"value": 32
"param": 100
}
还有这个:
{
"name": "Hello",
"value": 32
"param": {
"custom": true
}
}
如何实现?
我可以在 MyData
上定义自己的 MarshalJSON
和 UnmarshalJSON
并实现吗?
或者是否有定义自定义类型的方法,例如 IntOrStringOrCustom
并将 MyData
定义为
type MyData struct {
Name string `json:"name"`
Value int32 `json:"value"`
Param IntOrStringOrCustom `json:"param"`
}
然后在IntOrStringOrCustom
上定义MarshalJSON
和UnmarshalJSON
?
我也看过json.RawMessage
。我们可以在这里以某种方式使用它吗?
使用 interface{}
的问题是我将不得不在我尝试使用此数据的所有地方编写 encoding/decoding 逻辑。或者有没有一种优雅的方法可以使用 interface{}
?
已更新。 interface
会自动编码和解码为 JSON。如果你想控制类型,你可以添加特殊的 UnmarshalJSON
并在其中执行检查:
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
}
类型 InvalidFieldTypeError
可能方便 return 这样 class 的错误,可以定义为:
type InvalidFieldTypeError struct {
value interface{}
}
func (e InvalidFieldTypeError) Error() string {
return fmt.Sprintf("Field type '%T' is not valid for MyData", e.value)
}
整个例子:https://play.golang.org/p/MuW6gwSAKi
我也想推荐这篇文章https://attilaolah.eu/2013/11/29/json-decoding-in-go/
我正在尝试创建一个结构,其中一个字段可以保存一些特定类型的数据,例如 int
、string
和 CustomType
。我想 decode/encode 这个结构 to/from JSON。我们如何才能在 go/golang 中实现这一目标?
例如,我有一个用于以下定义的结构:
type MyData struct {
Name string `json:"name"`
Value int32 `json:"value"`
Param <can be either int, string or CustomType> `json:"param"`
}
其中 CustomType
是
type CustomType struct {
Custom bool `json:"custom"`
}
假设我需要将以下 JSON 解组到上面的结构 MyData
:
{
"name": "Hello",
"value": 32
"param": "World"
}
还有这个:
{
"name": "Hello",
"value": 32
"param": 100
}
还有这个:
{
"name": "Hello",
"value": 32
"param": {
"custom": true
}
}
如何实现?
我可以在 MyData
上定义自己的 MarshalJSON
和 UnmarshalJSON
并实现吗?
或者是否有定义自定义类型的方法,例如 IntOrStringOrCustom
并将 MyData
定义为
type MyData struct {
Name string `json:"name"`
Value int32 `json:"value"`
Param IntOrStringOrCustom `json:"param"`
}
然后在IntOrStringOrCustom
上定义MarshalJSON
和UnmarshalJSON
?
我也看过json.RawMessage
。我们可以在这里以某种方式使用它吗?
使用 interface{}
的问题是我将不得不在我尝试使用此数据的所有地方编写 encoding/decoding 逻辑。或者有没有一种优雅的方法可以使用 interface{}
?
已更新。 interface
会自动编码和解码为 JSON。如果你想控制类型,你可以添加特殊的 UnmarshalJSON
并在其中执行检查:
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
}
类型 InvalidFieldTypeError
可能方便 return 这样 class 的错误,可以定义为:
type InvalidFieldTypeError struct {
value interface{}
}
func (e InvalidFieldTypeError) Error() string {
return fmt.Sprintf("Field type '%T' is not valid for MyData", e.value)
}
整个例子:https://play.golang.org/p/MuW6gwSAKi
我也想推荐这篇文章https://attilaolah.eu/2013/11/29/json-decoding-in-go/