У меня есть значение int
/string
/bool
/etc.., хранящееся в interface{}
, и вы хотите определить, является ли оно неинициализированным, что означает, что оно имеет значение либо
-
0
-
""
-
false
- или
nil
Как это проверить?
У меня есть значение int
/string
/bool
/etc.., хранящееся в interface{}
, и вы хотите определить, является ли оно неинициализированным, что означает, что оно имеет значение либо
0
""
false
nil
Как это проверить?
Из того, что я понимаю, вы хотите что-то вроде:
func IsZeroOfUnderlyingType(x interface{}) bool {
return x == reflect.Zero(reflect.TypeOf(x)).Interface()
}
Говоря о интерфейсах и nil
, люди всегда путаются с двумя совершенно разными и несвязанными вещами:
nil
значение интерфейса, которое является значением интерфейса, которое не имеет базового значения. Это нулевое значение типа интерфейса.nil
(т.е. оно имеет базовое значение), но его базовое значение представляет собой нулевое значение его базового типа. например базовое значение представляет собой карту nil
, указатель nil
или 0 номер и т.д.Я понимаю, что вы спрашиваете о втором.
Обновление. Из-за вышеприведенного кода с помощью ==
он не будет работать для типов, которые не сопоставимы. Я считаю, что использование reflect.DeepEqual()
вместо этого сделает его работу для всех типов:
func IsZeroOfUnderlyingType(x interface{}) bool {
return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface())
}
нулевое значение * типа 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]
Ответ @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))
}
Переход 1.13 (Q3 2019) должен упростить этот процесс обнаружения:
Новый метод
Value.IsZero()
сообщает, является ли значение нулевым значением для его типа.
Он реализован в src/reflect/value.go
из commit c40bffd и CL 171337, что позволяет решить проблему 7501
Смотрите пример детской площадки (как только Go 1.13 будет поддерживаться)