Быстрый способ обнаружения пустых значений через отражение в Go
У меня есть значение int
/string
/bool
/etc.., хранящееся в interface{}
, и вы хотите определить, является ли оно неинициализированным, что означает, что оно имеет значение либо
Как это проверить?
Ответы
Ответ 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 будет поддерживаться)