github.com/wangyougui/gf/v2@v2.6.5/internal/empty/empty.go (about) 1 // Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 // Package empty provides functions for checking empty/nil variables. 8 package empty 9 10 import ( 11 "reflect" 12 "time" 13 14 "github.com/wangyougui/gf/v2/internal/reflection" 15 ) 16 17 // iString is used for type assert api for String(). 18 type iString interface { 19 String() string 20 } 21 22 // iInterfaces is used for type assert api for Interfaces. 23 type iInterfaces interface { 24 Interfaces() []interface{} 25 } 26 27 // iMapStrAny is the interface support for converting struct parameter to map. 28 type iMapStrAny interface { 29 MapStrAny() map[string]interface{} 30 } 31 32 type iTime interface { 33 Date() (year int, month time.Month, day int) 34 IsZero() bool 35 } 36 37 // IsEmpty checks whether given `value` empty. 38 // It returns true if `value` is in: 0, nil, false, "", len(slice/map/chan) == 0, 39 // or else it returns false. 40 // 41 // The parameter `traceSource` is used for tracing to the source variable if given `value` is type of pointer 42 // that also points to a pointer. It returns true if the source is empty when `traceSource` is true. 43 // Note that it might use reflect feature which affects performance a little. 44 func IsEmpty(value interface{}, traceSource ...bool) bool { 45 if value == nil { 46 return true 47 } 48 // It firstly checks the variable as common types using assertion to enhance the performance, 49 // and then using reflection. 50 switch result := value.(type) { 51 case int: 52 return result == 0 53 case int8: 54 return result == 0 55 case int16: 56 return result == 0 57 case int32: 58 return result == 0 59 case int64: 60 return result == 0 61 case uint: 62 return result == 0 63 case uint8: 64 return result == 0 65 case uint16: 66 return result == 0 67 case uint32: 68 return result == 0 69 case uint64: 70 return result == 0 71 case float32: 72 return result == 0 73 case float64: 74 return result == 0 75 case bool: 76 return !result 77 case string: 78 return result == "" 79 case []byte: 80 return len(result) == 0 81 case []rune: 82 return len(result) == 0 83 case []int: 84 return len(result) == 0 85 case []string: 86 return len(result) == 0 87 case []float32: 88 return len(result) == 0 89 case []float64: 90 return len(result) == 0 91 case map[string]interface{}: 92 return len(result) == 0 93 94 default: 95 // Finally, using reflect. 96 var rv reflect.Value 97 if v, ok := value.(reflect.Value); ok { 98 rv = v 99 } else { 100 // ========================= 101 // Common interfaces checks. 102 // ========================= 103 if f, ok := value.(iTime); ok { 104 if f == (*time.Time)(nil) { 105 return true 106 } 107 return f.IsZero() 108 } 109 if f, ok := value.(iString); ok { 110 if f == nil { 111 return true 112 } 113 return f.String() == "" 114 } 115 if f, ok := value.(iInterfaces); ok { 116 if f == nil { 117 return true 118 } 119 return len(f.Interfaces()) == 0 120 } 121 if f, ok := value.(iMapStrAny); ok { 122 if f == nil { 123 return true 124 } 125 return len(f.MapStrAny()) == 0 126 } 127 128 rv = reflect.ValueOf(value) 129 } 130 131 switch rv.Kind() { 132 case reflect.Bool: 133 return !rv.Bool() 134 135 case 136 reflect.Int, 137 reflect.Int8, 138 reflect.Int16, 139 reflect.Int32, 140 reflect.Int64: 141 return rv.Int() == 0 142 143 case 144 reflect.Uint, 145 reflect.Uint8, 146 reflect.Uint16, 147 reflect.Uint32, 148 reflect.Uint64, 149 reflect.Uintptr: 150 return rv.Uint() == 0 151 152 case 153 reflect.Float32, 154 reflect.Float64: 155 return rv.Float() == 0 156 157 case reflect.String: 158 return rv.Len() == 0 159 160 case reflect.Struct: 161 var fieldValueInterface interface{} 162 for i := 0; i < rv.NumField(); i++ { 163 fieldValueInterface, _ = reflection.ValueToInterface(rv.Field(i)) 164 if !IsEmpty(fieldValueInterface) { 165 return false 166 } 167 } 168 return true 169 170 case 171 reflect.Chan, 172 reflect.Map, 173 reflect.Slice, 174 reflect.Array: 175 return rv.Len() == 0 176 177 case reflect.Ptr: 178 if len(traceSource) > 0 && traceSource[0] { 179 return IsEmpty(rv.Elem()) 180 } 181 return rv.IsNil() 182 183 case 184 reflect.Func, 185 reflect.Interface, 186 reflect.UnsafePointer: 187 return rv.IsNil() 188 189 case reflect.Invalid: 190 return true 191 } 192 } 193 return false 194 } 195 196 // IsNil checks whether given `value` is nil, especially for interface{} type value. 197 // Parameter `traceSource` is used for tracing to the source variable if given `value` is type of pointer 198 // that also points to a pointer. It returns nil if the source is nil when `traceSource` is true. 199 // Note that it might use reflect feature which affects performance a little. 200 func IsNil(value interface{}, traceSource ...bool) bool { 201 if value == nil { 202 return true 203 } 204 var rv reflect.Value 205 if v, ok := value.(reflect.Value); ok { 206 rv = v 207 } else { 208 rv = reflect.ValueOf(value) 209 } 210 switch rv.Kind() { 211 case reflect.Chan, 212 reflect.Map, 213 reflect.Slice, 214 reflect.Func, 215 reflect.Interface, 216 reflect.UnsafePointer: 217 return !rv.IsValid() || rv.IsNil() 218 219 case reflect.Ptr: 220 if len(traceSource) > 0 && traceSource[0] { 221 for rv.Kind() == reflect.Ptr { 222 rv = rv.Elem() 223 } 224 if !rv.IsValid() { 225 return true 226 } 227 if rv.Kind() == reflect.Ptr { 228 return rv.IsNil() 229 } 230 } else { 231 return !rv.IsValid() || rv.IsNil() 232 } 233 } 234 return false 235 }