Разница между пропущенными и пустыми полями в JSON unmarshalling - PullRequest
0 голосов
/ 27 мая 2019

Итак, у меня есть эта структура в Go:

type Car struct {
    Name  string `json:"name"`
    Speed int    `json:"speed"`
}

И у меня есть два образца JSON, которые я демарширую:

str := `{"name": "", "speed": 0}`
strTwo := `{}`

Я выполняю демаршалинг следующим образом:

car := Car{}
_ = json.Unmarshal([]byte(str), &car)

carTwo := Car{}
_ = json.Unmarshal([]byte(strTwo), &carTwo)

Теперь из-за того, как Go работает с типами значений по умолчанию, когда я пытаюсь напечатать структуру, я получаю тот же результат:

car - { 0}
carTwo - { 0}

Так что я не вижу разницы междуотсутствующее значение в JSON и когда передается значение по умолчанию.Как я могу решить эту проблему?

Одним из способов является использование указателей в структуре:

type Car struct {
    Name  *string `json:"name"`
    Speed *int    `json:"speed"`
}

Но я получаю очень некрасивый код при использовании этих значений, я должен везде разыменовывать указатели

1 Ответ

2 голосов
/ 27 мая 2019

Примитивные типы данных Go не подходят для обработки "всех допустимых значений", и дополнительная информация "присутствует".

Если вам это нужно, одним из способов является использование указателей, где nil значение указателя соответствует «отсутствующему» состоянию.

Если впоследствии работать с указателями неудобно, выполните «постобработку»: преобразуйте свои структуры с полями указателя в значение структуры с полями без указателя,так что вы можете работать с этим позже.

Вы можете сделать это «вручную» или написать собственный демаршалер, чтобы это произошло автоматически.

Вот пример, как это сделать:

type PCar struct {
    Name  *string `json:"name"`
    Speed *int    `json:"speed"`
}

type Car struct {
    Name  string `json:"-"`
    Speed int    `json:"-"`
    PCar
}

func (c *Car) UnmarshalJSON(data []byte) error {
    if err := json.Unmarshal(data, &c.PCar); err != nil {
        return err
    }

    if c.PCar.Name != nil {
        c.Name = *c.PCar.Name
    }
    if c.PCar.Speed != nil {
        c.Speed = *c.PCar.Speed
    }
    return nil
}

Пример использования:

sources := []string{
    `{"name": "", "speed": 0}`,
    `{}`,
    `{"name": "Bob", "speed": 21}`,
}

for i, src := range sources {
    var c Car
    if err := json.Unmarshal([]byte(src), &c); err != nil {
        panic(err)
    }
    fmt.Println("car", i, c)
}

Вывод (попробуйте на Go Playground ):

car 0 { 0 {0x40c200 0x4140ac}}
car 1 { 0 {<nil> <nil>}}
car 2 {Bob 21 {0x40c218 0x41410c}}

Как видите,car 1 содержит 2 не nil указателя, потому что соответствующие поля присутствовали во входном JSON, в то время как car 2 содержит 2 nil указателей, потому что эти поля отсутствовали во входных данных.Вы можете использовать поля Car.Name и Car.Speed как не указатели (потому что они не указатели).Чтобы узнать, присутствовали ли они на входе, вы можете проверить соответствующие указатели Car.PCar.Name и Car.PCar.Speed, если они nil.

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