Подтвердить что ты не робот

Быстрый способ обнаружения пустых значений через отражение в Go

У меня есть значение int/string/bool/etc.., хранящееся в interface{}, и вы хотите определить, является ли оно неинициализированным, что означает, что оно имеет значение либо

  • 0
  • ""
  • false
  • или nil

Как это проверить?

4b9b3361

Ответ 1

Из того, что я понимаю, вы хотите что-то вроде:

func IsZeroOfUnderlyingType(x interface{}) bool {
    return x == reflect.Zero(reflect.TypeOf(x)).Interface()
}

Говоря о интерфейсах и nil, люди всегда путаются с двумя совершенно разными и несвязанными вещами:

  • A nil значение интерфейса, которое является значением интерфейса, которое не имеет базового значения. Это нулевое значение типа интерфейса.
  • Значение интерфейса не nil (т.е. оно имеет базовое значение), но его базовое значение представляет собой нулевое значение его базового типа. например базовое значение представляет собой карту nil, указатель nil или 0 номер и т.д.

Я понимаю, что вы спрашиваете о втором.


Обновление. Из-за вышеприведенного кода с помощью == он не будет работать для типов, которые не сопоставимы. Я считаю, что использование reflect.DeepEqual() вместо этого сделает его работу для всех типов:

func IsZeroOfUnderlyingType(x interface{}) bool {
    return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface())
}

Ответ 2

нулевое значение * типа interface{} - это только nil, а не 0 или "" или false.

package main

import "fmt"

func main() {
        var v interface{}
        fmt.Println(v == nil, v == 0, v == "", v == false)
}

(Также http://play.golang.org/p/z1KbX1fOgB)


Выход

true false false false

*: [Q] Когда память выделена для хранения значения, либо через объявление, либо вызов make, либо новый, и явная инициализация не предоставляется, памяти присваивается инициализация по умолчанию. Каждому элементу такого значения присваивается нулевое значение для его типа: false для booleans, 0 для целых чисел, 0.0 для float, "" для строк и nil для указателей, функций, интерфейсов, срезов, каналов и карт. [/Q]

Ответ 3

Ответ @newacct не может обнаружить необработанное нулевое значение, вызывая reflect.Value.Interface(), что приведет к ошибке. Он может использовать reflect.Value.IsValid(), чтобы проверить это.

// IsValid reports whether v represents a value.
// It returns false if v is the zero Value.
// If IsValid returns false, all other methods except String panic.
// Most functions and methods never return an invalid value.
// If one does, its documentation states the conditions explicitly.
func (v Value) IsValid() bool 

Обновить методы:

func IsZero(v reflect.Value) bool {
    return !v.IsValid() || reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}

func TestIsZero(t *testing.T) {
    var p *string
    v := reflect.ValueOf(p)

    assert.Equal(t, true, v.IsValid())
    assert.True(t, IsZero(v))

    assert.Equal(t, uintptr(0), v.Pointer())

    v = v.Elem()
    assert.Equal(t, false, v.IsValid())
    assert.True(t, IsZero(v))
}

Ответ 4

Переход 1.13 (Q3 2019) должен упростить этот процесс обнаружения:

Новый метод Value.IsZero() сообщает, является ли значение нулевым значением для его типа.

Он реализован в src/reflect/value.go из commit c40bffd и CL 171337, что позволяет решить проблему 7501

Смотрите пример детской площадки (как только Go 1.13 будет поддерживаться)