Unmarshal для пользовательского интерфейса - PullRequest
0 голосов
/ 12 октября 2018

Обычный подход для демаршаллинга такой:

atmosphereMap := make(map[string]interface{})
err := json.Unmarshal(bytes, &atmosphereMap)

Но как демаршировать json данные в пользовательский интерфейс:

type CustomInterface interface {
    G() float64
} 

atmosphereMap := make(map[string]CustomInterface)
err := json.Unmarshal(bytes, &atmosphereMap)

Второй способ дает мне ошибку:

panic: json: cannot unmarshal object into Go value of type main.CustomInterface

Как это правильно сделать?

1 Ответ

0 голосов
/ 12 октября 2018

Чтобы разобрать набор типов, которые все реализуют общий интерфейс, вы можете реализовать интерфейс json.Unmarshaler для родительского типа, map[string]CustomInterface в вашем случае:

type CustomInterfaceMap map[string]CustomInterface

func (m CustomInterfaceMap) UnmarshalJSON(b []byte) error {
    data := make(map[string]json.RawMessage)
    if err := json.Unmarshal(b, &data); err != nil {
        return err
    }
    for k, v := range data {
        var dst CustomInterface
        // populate dst with an instance of the actual type you want to unmarshal into
        if _, err := strconv.Atoi(string(v)); err == nil {
            dst = &CustomImplementationInt{} // notice the dereference
        } else {
            dst = &CustomImplementationFloat{}
        }

        if err := json.Unmarshal(v, dst); err != nil {
            return err
        }
        m[k] = dst
    }
    return nil
}

Полный пример см. На этой площадке .Убедитесь, что вы отменяете маршализацию в CustomInterfaceMap, а не map[string]CustomInterface, в противном случае пользовательский метод UnmarshalJSON вызываться не будет.

json.RawMessage - это полезный тип, который простонеобработанное закодированное значение JSON, то есть это простое []byte, в котором JSON хранится в неразобранной форме.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...