自定义解组为一种类型而不是输入不同的类型

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"`
}

我创建了一个自定义 UnmarshallJSON 函数来解组此结构,因为作为输入我有:

我希望当输入为 false 时,信息为零。

这是 UnmarshallJSON 函数

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
}

太丑了,想知道有没有更好的选择。 非常感谢。

首先,您应该对意外的类型和长度更加谨慎,以避免恐慌。然后您可以解组为 []json.RawMessage 以推迟元素的解组,直到您准备好。最后你应该提防你的无效 true.

这是我的最大努力,请其他人随意编辑(here是一个游乐场):

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
}