Fix zero
This commit is contained in:
parent
89002a2625
commit
83efadad5a
|
@ -13,7 +13,14 @@ type Zeroable interface {
|
||||||
IsZero() bool
|
IsZero() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var nilTime *time.Time
|
||||||
|
|
||||||
|
// IsZero returns false if k is nil or has a zero value
|
||||||
func IsZero(k interface{}) bool {
|
func IsZero(k interface{}) bool {
|
||||||
|
if k == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
switch k.(type) {
|
switch k.(type) {
|
||||||
case int:
|
case int:
|
||||||
return k.(int) == 0
|
return k.(int) == 0
|
||||||
|
@ -43,31 +50,57 @@ func IsZero(k interface{}) bool {
|
||||||
return k.(bool) == false
|
return k.(bool) == false
|
||||||
case string:
|
case string:
|
||||||
return k.(string) == ""
|
return k.(string) == ""
|
||||||
|
case *time.Time:
|
||||||
|
return k.(*time.Time) == nilTime || IsTimeZero(*k.(*time.Time))
|
||||||
|
case time.Time:
|
||||||
|
return IsTimeZero(k.(time.Time))
|
||||||
case Zeroable:
|
case Zeroable:
|
||||||
return k.(Zeroable).IsZero()
|
return k.(Zeroable) == nil || k.(Zeroable).IsZero()
|
||||||
}
|
case reflect.Value: // for go version less than 1.13 because reflect.Value has no method IsZero
|
||||||
return false
|
return IsValueZero(k.(reflect.Value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return IsValueZero(reflect.ValueOf(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
var zeroType = reflect.TypeOf((*Zeroable)(nil)).Elem()
|
||||||
|
|
||||||
func IsValueZero(v reflect.Value) bool {
|
func IsValueZero(v reflect.Value) bool {
|
||||||
if IsZero(v) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if IsZero(v.Interface()) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Slice:
|
||||||
return v.IsNil()
|
return v.IsNil()
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
|
||||||
|
return v.Int() == 0
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
|
||||||
|
return v.Uint() == 0
|
||||||
|
case reflect.String:
|
||||||
|
return v.Len() == 0
|
||||||
|
case reflect.Ptr:
|
||||||
|
if v.IsNil() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return IsValueZero(v.Elem())
|
||||||
|
case reflect.Struct:
|
||||||
|
return IsStructZero(v)
|
||||||
|
case reflect.Array:
|
||||||
|
return IsArrayZero(v)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsStructZero(v reflect.Value) bool {
|
func IsStructZero(v reflect.Value) bool {
|
||||||
if !v.IsValid() {
|
if !v.IsValid() || v.NumField() == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if v.Type().Implements(zeroType) {
|
||||||
|
f := v.MethodByName("IsZero")
|
||||||
|
if f.IsValid() {
|
||||||
|
res := f.Call(nil)
|
||||||
|
return len(res) == 1 && res[0].Bool()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < v.NumField(); i++ {
|
for i := 0; i < v.NumField(); i++ {
|
||||||
field := v.Field(i)
|
field := v.Field(i)
|
||||||
switch field.Kind() {
|
switch field.Kind() {
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright 2020 The Xorm Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MyInt int
|
||||||
|
type ZeroStruct struct{}
|
||||||
|
|
||||||
|
func TestZero(t *testing.T) {
|
||||||
|
var zeroValues = []interface{}{
|
||||||
|
int8(0),
|
||||||
|
int16(0),
|
||||||
|
int(0),
|
||||||
|
int32(0),
|
||||||
|
int64(0),
|
||||||
|
uint8(0),
|
||||||
|
uint16(0),
|
||||||
|
uint(0),
|
||||||
|
uint32(0),
|
||||||
|
uint64(0),
|
||||||
|
MyInt(0),
|
||||||
|
reflect.ValueOf(0),
|
||||||
|
nil,
|
||||||
|
time.Time{},
|
||||||
|
&time.Time{},
|
||||||
|
nilTime,
|
||||||
|
ZeroStruct{},
|
||||||
|
&ZeroStruct{},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range zeroValues {
|
||||||
|
t.Run(fmt.Sprintf("%#v", v), func(t *testing.T) {
|
||||||
|
assert.True(t, IsZero(v))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsValueZero(t *testing.T) {
|
||||||
|
var zeroReflectValues = []reflect.Value{
|
||||||
|
reflect.ValueOf(int8(0)),
|
||||||
|
reflect.ValueOf(int16(0)),
|
||||||
|
reflect.ValueOf(int(0)),
|
||||||
|
reflect.ValueOf(int32(0)),
|
||||||
|
reflect.ValueOf(int64(0)),
|
||||||
|
reflect.ValueOf(uint8(0)),
|
||||||
|
reflect.ValueOf(uint16(0)),
|
||||||
|
reflect.ValueOf(uint(0)),
|
||||||
|
reflect.ValueOf(uint32(0)),
|
||||||
|
reflect.ValueOf(uint64(0)),
|
||||||
|
reflect.ValueOf(MyInt(0)),
|
||||||
|
reflect.ValueOf(time.Time{}),
|
||||||
|
reflect.ValueOf(&time.Time{}),
|
||||||
|
reflect.ValueOf(nilTime),
|
||||||
|
reflect.ValueOf(ZeroStruct{}),
|
||||||
|
reflect.ValueOf(&ZeroStruct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range zeroReflectValues {
|
||||||
|
t.Run(fmt.Sprintf("%#v", v), func(t *testing.T) {
|
||||||
|
assert.True(t, IsValueZero(v))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue