github.com/gogf/gf/v2@v2.7.4/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/gogf/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/gogf/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 rv = reflect.ValueOf(value) 101 if IsNil(rv) { 102 return true 103 } 104 105 // ========================= 106 // Common interfaces checks. 107 // ========================= 108 if f, ok := value.(iTime); ok { 109 if f == (*time.Time)(nil) { 110 return true 111 } 112 return f.IsZero() 113 } 114 if f, ok := value.(iString); ok { 115 if f == nil { 116 return true 117 } 118 return f.String() == "" 119 } 120 if f, ok := value.(iInterfaces); ok { 121 if f == nil { 122 return true 123 } 124 return len(f.Interfaces()) == 0 125 } 126 if f, ok := value.(iMapStrAny); ok { 127 if f == nil { 128 return true 129 } 130 return len(f.MapStrAny()) == 0 131 } 132 } 133 134 switch rv.Kind() { 135 case reflect.Bool: 136 return !rv.Bool() 137 138 case 139 reflect.Int, 140 reflect.Int8, 141 reflect.Int16, 142 reflect.Int32, 143 reflect.Int64: 144 return rv.Int() == 0 145 146 case 147 reflect.Uint, 148 reflect.Uint8, 149 reflect.Uint16, 150 reflect.Uint32, 151 reflect.Uint64, 152 reflect.Uintptr: 153 return rv.Uint() == 0 154 155 case 156 reflect.Float32, 157 reflect.Float64: 158 return rv.Float() == 0 159 160 case reflect.String: 161 return rv.Len() == 0 162 163 case reflect.Struct: 164 var fieldValueInterface interface{} 165 for i := 0; i < rv.NumField(); i++ { 166 fieldValueInterface, _ = reflection.ValueToInterface(rv.Field(i)) 167 if !IsEmpty(fieldValueInterface) { 168 return false 169 } 170 } 171 return true 172 173 case 174 reflect.Chan, 175 reflect.Map, 176 reflect.Slice, 177 reflect.Array: 178 return rv.Len() == 0 179 180 case reflect.Ptr: 181 if len(traceSource) > 0 && traceSource[0] { 182 return IsEmpty(rv.Elem()) 183 } 184 return rv.IsNil() 185 186 case 187 reflect.Func, 188 reflect.Interface, 189 reflect.UnsafePointer: 190 return rv.IsNil() 191 192 case reflect.Invalid: 193 return true 194 195 default: 196 return false 197 } 198 } 199 } 200 201 // IsNil checks whether given `value` is nil, especially for interface{} type value. 202 // Parameter `traceSource` is used for tracing to the source variable if given `value` is type of pointer 203 // that also points to a pointer. It returns nil if the source is nil when `traceSource` is true. 204 // Note that it might use reflect feature which affects performance a little. 205 func IsNil(value interface{}, traceSource ...bool) bool { 206 if value == nil { 207 return true 208 } 209 var rv reflect.Value 210 if v, ok := value.(reflect.Value); ok { 211 rv = v 212 } else { 213 rv = reflect.ValueOf(value) 214 } 215 switch rv.Kind() { 216 case reflect.Chan, 217 reflect.Map, 218 reflect.Slice, 219 reflect.Func, 220 reflect.Interface, 221 reflect.UnsafePointer: 222 return !rv.IsValid() || rv.IsNil() 223 224 case reflect.Ptr: 225 if len(traceSource) > 0 && traceSource[0] { 226 for rv.Kind() == reflect.Ptr { 227 rv = rv.Elem() 228 } 229 if !rv.IsValid() { 230 return true 231 } 232 if rv.Kind() == reflect.Ptr { 233 return rv.IsNil() 234 } 235 } else { 236 return !rv.IsValid() || rv.IsNil() 237 } 238 239 default: 240 return false 241 } 242 return false 243 }