Зачем идти json.Unmarshal интерфейс автоматического преобразования {} на карту - PullRequest
0 голосов
/ 01 марта 2019

Программа будет получать много сообщений, у msg есть другая структура "Данные", поэтому я определяю структуру Msg:

type Msg struct {
    MsgType int
    Data interface{}
}
type Data1 struct {
//msg type 1 Data struct
}
type Data2 struct {
//msg type 2 Data struct
}
func (msgStr string) {
    msg := Msg{}
    if err := json.Unmarshal([]byte(msgStr), &msg); err != nil {
        //log err
    }
    switch msg.MsgType{
    case 1:
        //convert msg.Data to a type 1 struct
    case 2:
        //convert msg.Data to a type 2 struct
    }
}

Но выведите сообщение msg.Data, это карта, а не интерфейс {}, поэтому, когда я преобразовываю его в Data1 с помощью msg.Data. (Data1), получаю ошибку.
Итак,
1. Почему интерфейс {} автоматически преобразуется в карту?
2. Как преобразовать егов Data1 struct, которую я хочу?
3. Каковы лучшие практики в этих сценах.

1 Ответ

0 голосов
/ 01 марта 2019

1.Поскольку он видит объект JSON, и, как задокументировано, объект JSON становится map[string]interface{} при сохранении в interface{} (это единственный тип, который может содержать все, что находится в объекте JSON в целом).

2.Учитывая текущую ситуацию, вы можете назначить каждое поле карты соответствующему полю нового Data1 или Data2.

3.Идеальный способ справиться с этим - использовать json.RawMessage для отсрочки декодирования Data, пока вы не узнаете, что это такое.Это может быть обработано следующим образом:

type Msg struct {
  MsgType int
  Data interface{}
}

func (m *Msg) UnmarshalJSON(b []byte) (err error) {
    var tmp struct {
        MsgType int
        Data json.RawMessage
    }
    err = json.Unmarshal(b, &tmp)
    if err != nil {
        return
    }
    m.MsgType = tmp.MsgType
    switch (tmp.MsgType) {
    case 1:
        data := Data1{}
        err = json.Unmarshal(tmp.Data, &data)
        if err != nil {
            return
        }
        m.Data = data
    case 2:
        data := Data2{}
        err = json.Unmarshal(tmp.Data, &data)
        if err != nil {
            return
        }
        m.Data = data
    default:
        return errors.New("invalid DataType")
    }
    return
}

И тогда вы можете позвонить json.Unmarshal или json.Decode непосредственно на *Msg, и его Data будет декодирован, как вы хотите.

...