Проверьте, является ли поле структуры пустым - PullRequest
0 голосов
/ 30 мая 2018

Я бы хотел перебрать поля struct после демаршаллинга объекта JSON в него и проверить поля, значение которых не было установлено (т. Е. Пусто).

Я могу получить значениекаждого поля и сравните его со значением reflect.Zero для соответствующего типа

json.Unmarshal([]byte(str), &res)
s := reflect.ValueOf(&res).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField(); i++ {
    f := s.Field(i)
    v := reflect.ValueOf(f.Interface())
    if (reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())) {
    ....

Но проблема, конечно, в том, что это не будет работать хорошо для значений bool или int.Если для поля bool установлено значение false в JSON или для поля int установлено значение 0, они будут равны нулевому значению их типа.Вышеупомянутая проверка будет считать поля неинициализированными, даже если они на самом деле имеют установленное значение.

Я знаю, что одним из способов решения этой проблемы является использование указателей, но я просто не вижу, как это было бы возможно вв этом случае я работаю с reflect.Value типами, а не с struct.

Ответы [ 3 ]

0 голосов
/ 30 мая 2018

Еще один способ сделать то же самое - реализовать json.Unmarshaler.

type MaybeInt struct {
    Present bool
    Value   int
}

func (i *MaybeInt) UnmarshalJSON(bs []byte) error {
    if e := json.Unmarshal(bs, &i.Value); e != nil {
        return e
    }
    i.Present = true
    return nil
}

Затем вы можете использовать MaybeInt в структуре верхнего уровня:

type Top struct {
    N MaybeInt `json:"n"`
    M MaybeInt `json:"m"`
}

func main() {
    t := Top{}
    if e := json.Unmarshal([]byte(` { "n": 4930 } `), &t); e != nil {
        panic(e)
    }
    fmt.Println(t.N, t.M)
}

Посмотрите, как это работает на детской площадке

0 голосов
/ 30 мая 2018

Попробуйте использовать пакет валидатора golang.Пакет валидатора предлагает атрибут required , который может выполнить требуемую работу для ваших нужд.Официальная документация для обязательных состояний атрибутов:

Это подтверждает, что значение не является нулевым значением по умолчанию для типов данных.Для чисел гарантируется, что значение не равно нулю.Для строк обеспечивает значение не "".Для срезов, карт, указателей, интерфейсов, каналов и функций гарантируется, что значение не равно nil.

Пример, иллюстрирующий то же самое, можно увидеть по адресу: https://github.com/go-playground/validator/blob/v9/_examples/struct-level/main.go.

Надеюсь, это решитваше требование.

0 голосов
/ 30 мая 2018

Как вы упомянули, вы можете использовать указатели.

Пакет json может обрабатывать неверные значения в указатели для вас.Вы не включили полезную нагрузку json, которую вы пытаетесь демонтировать, или структуру, в которую вы демаршируете, поэтому я составил пример.

// json
{
    "foo": true,
    "number_of_foos": 14
}

// go struct
type Foo struct {
    Present bool `json:"foo"`
    Num     int  `json:"number_of_foos"`
}

Здесь, если ключи foo или number_of_foos отсутствует, тогда, как вы правильно заметили, будет использовано нулевое значение (false / 0).В общем, лучший совет - использовать нулевое значение .Создайте структуры так, чтобы нулевые значения false были полезными, а не болезненными.Это не всегда возможно, поэтому изменение типов полей в структуре Foo на указатели позволит вам проверить 3 случая, которые вы ищете.

  1. Present
  2. Настоящее и ноль
  3. Отсутствует

Здесь та же структура с указателями:

// go struct
type Foo struct {
    Present *bool `json:"foo"`
    Num     *int  `json:"number_of_foos"`
}

Теперь вы можете проверить наличие значения с помощью fooStruct.Present != nil иесли это условие выполняется, вы можете предположить, что значение в поле является тем, которое вы хотели.

Нет необходимости использовать пакет отражения.

...