Пользовательский UnmarshalJSON не вызывается

#json #go #interface #unmarshalling #go-interface

# #json #Вперед #интерфейс #отмена сопоставления #go-интерфейс

Вопрос:

У меня есть интерфейс, который реализован несколькими структурами. В одном из моих методов я создаю экземпляр struct base для заданной строки, а затем анализирую json в определенную структуру. Для этого я реализовал UnmarshalJSON, но он никогда не вызывается.

Интерфейс:

 type vehicle interface {
    vehicleType() string
    numberOfWheels() int
    EngineType() string
}
 

Две структуры, реализующие интерфейс:

 type truck struct {
    loadCapacity  int
    capacityUnits string
}

func (t truck) vehicleType() string {
    return "Truck"
}

func (t truck) numberOfWheels() int {
    return 6
}

func (t truck) EngineType() string {
    return "Gasoline"
}

func (t *truck) UnmarshalJSON(data []byte) error {
    fmt.Println("Here in custom unmarshal")
    return nil
}

// -------------------------------------------
type ev struct {
    capacityInKWh int
}

func (e ev) vehicleType() string {
    return "Electric Vehicle"
}

func (e ev) numberOfWheels() int {
    return 4
}

func (e ev) EngineType() string {
    return "Electric"
}

func (e ev) Capacity() int {
    return e.capacityInKWh
}
 

Обратите внимание, что моя truck структура также реализует пользовательский UnmarshalJSON.

Теперь, в основном, я пытаюсь сделать следующее:

 func main() {
    jsonData := []byte(`{"loadCapacity": 1000, "capacityUnits": "lb"}`)
    vehicleType := "truck"

    processVehicle(vehicleType, jsonData)
}

func processVehicle(vehicleType string, data []byte) {
    var myVehicle vehicle

    fmt.Println("Processing vehicle...")

    switch vehicleType {
    case "truck":
        myVehicle = truck{}
    }

    err := json.Unmarshal(data, amp;myVehicle)
    if err != nil {
        fmt.Println(err.Error())
        return
    }

    fmt.Println(myVehicle)
}
 

Но я получаю следующую ошибку:

json: невозможно преобразовать объект в исходное значение типа main.vehicle

Я знаю, что в реализованном for нет фактического тела UnmarshalJSON truck , но я бы ожидал, что хотя бы сообщение будет напечатано.

Что я делаю не так?

Комментарии:

1. Таким truck образом, реализуется json.Unmarshaler интерфейс, но вы разархивируете в type vehicle , который является просто интерфейсом, так что это не работает. Вам нужно разобрать значение в конкретное truck значение.

2. @Flimzy но я не буду знать, какой тип транспортного processVehicle средства будет получен. Есть ли способ обойти это? Я имею в виду, я не хочу реализовывать несколько switch повсюду

3. Тогда все, что включает vehicle , должно принять решение о том, в какой тип разархивировать.

4. Вам где -то нужен какой-то оператор switch (или эквивалентная логика). В Go нет волшебства.

5. В этом видео я рассказываю об использовании объекта контейнера для аналогичной ситуации, о которой @JimB, похоже, ускользнул.

Ответ №1:

Функция JSONUnmarshal находится в приемнике указателя. Используйте значение указателя для доступа к этому методу.

 switch vehicleType {
case "truck":
    myVehicle = amp;truck{}  // <-- add amp; here
}

err := json.Unmarshal(data, myVehicle) // <-- amp; not needed here
 

Запустите его на игровой площадке Go.

Комментарии:

1. Это не связано с проблемой, связанной с вопросом.