This commit is contained in:
Lunny Xiao 2020-03-09 14:35:35 +08:00
parent 89002a2625
commit 83efadad5a
No known key found for this signature in database
GPG Key ID: C3B7C91B632F738A
2 changed files with 116 additions and 10 deletions

View File

@ -13,7 +13,14 @@ type Zeroable interface {
IsZero() bool
}
var nilTime *time.Time
// IsZero returns false if k is nil or has a zero value
func IsZero(k interface{}) bool {
if k == nil {
return true
}
switch k.(type) {
case int:
return k.(int) == 0
@ -43,31 +50,57 @@ func IsZero(k interface{}) bool {
return k.(bool) == false
case 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:
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 IsValueZero(k.(reflect.Value))
}
return false
return IsValueZero(reflect.ValueOf(k))
}
var zeroType = reflect.TypeOf((*Zeroable)(nil)).Elem()
func IsValueZero(v reflect.Value) bool {
if IsZero(v) {
return true
}
if IsZero(v.Interface()) {
return true
}
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()
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
}
func IsStructZero(v reflect.Value) bool {
if !v.IsValid() {
if !v.IsValid() || v.NumField() == 0 {
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++ {
field := v.Field(i)
switch field.Kind() {

View File

@ -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))
})
}
}