英文:
Custom unmarshall to a type than input out different type
问题
我正在学习Go,并且有一个问题:
我有一个Info
类型的结构体,定义如下:
type Info struct {
ID ID `json:"id,omitempty"`
DisplayName string `json:"display_name,omitempty"`
}
我编写了一个自定义的UnmarshalJSON
函数来解析这个结构体,因为作为输入,我可能有以下两种情况:
- 一个
[]interface{}
,在位置[0]上是一个int,位置1上是一个string - 一个布尔值,始终等于
false
,表示该字段为null
我希望当输入为false
时,Info
为nil
。
以下是UnmarshalJSON
函数的代码:
func (i *Info) UnmarshalJSON(data []byte) error {
var v []interface{}
if err := json.Unmarshal(data, &v); err != nil {
var v bool
if err = json.Unmarshal(data, &v); err != nil {
return err
}
return nil
}
i.ID = ID(v[0].(float64))
i.DisplayName = v[1].(string)
return nil
}
这段代码看起来有些丑陋,我想知道是否有更好的选择。非常感谢。
英文:
I'm learning Go and I have a question:
I have an Info
type that is defined like that:
type Info struct {
ID ID `json:"id,omitempty"`
DisplayName string `json:"display_name,omitempty"`
}
I made a custom UnmarshallJSON
function to unmarshall this struct because as an input I have either:
- An
[]interface{}
with at position [0] an int and 1 a string - A
boolean
always equals tofalse
meaning that the field isnull
I want that when the input is false
, the Info is nil.
Here's the UnmarshallJSON
function
func (i *Info) UnmarshalJSON(data []byte) error {
var v []interface{}
if err := json.Unmarshal(data, &v); err != nil {
var v bool
if err = json.Unmarshal(data, &v); err != nil {
return err
}
return nil
}
i.ID = ID(v[0].(float64))
i.DisplayName = v[1].(string)
return nil
}
It's ugly, and I would like to know if there's a better option.
Thank you very much.
答案1
得分: 0
首先,你应该更加谨慎地处理意外的类型和长度,以避免出现错误。然后,你可以将其解组为[]json.RawMessage
,以延迟对元素的解组,直到你准备好进行解组。最后,你应该防止出现无效的true
。
以下是我最好的努力,请其他人随意编辑(这里是一个示例):
func (i *Info) UnmarshalJSON(data []byte) error {
var raw interface{}
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
switch r := raw.(type) {
case []interface{}:
case bool:
if r {
return errors.New("unexpected true, must be array or false")
}
return nil
default:
return fmt.Errorf("unexpected type %T, must be array or false", r)
}
var v []json.RawMessage
if err := json.Unmarshal(data, &v); err != nil {
return err
}
if len(v) != 2 {
return fmt.Errorf("unexpected length %d, must be 2", len(v))
}
if err := json.Unmarshal(v[0], &i.ID); err != nil {
return err
}
if err := json.Unmarshal(v[1], &i.DisplayName); err != nil {
return err
}
return nil
}
英文:
Fist you should be more defensive about unexpected types and length to avoid a panic. Then you can unmarshal into a []json.RawMessage
to defer unmarshaling of the elements until you are ready. Finally you should guard against your invalid true
.
Here is my best effort, please others feel free to edit (here is a playground):
func (i *Info) UnmarshalJSON(data []byte) error {
var raw interface{}
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
switch r := raw.(type) {
case []interface{}:
case bool:
if r {
return errors.New("unexpected true, must be array or false")
}
return nil
default:
return fmt.Errorf("unexpected type %T, must be array or false", r)
}
var v []json.RawMessage
if err := json.Unmarshal(data, &v); err != nil {
return err
}
if len(v) != 2 {
return fmt.Errorf("unexpected length %d, must be 2", len(v))
}
if err := json.Unmarshal(v[0], &i.ID); err != nil {
return err
}
if err := json.Unmarshal(v[1], &i.DisplayName); err != nil {
return err
}
return nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论