empty.go 5.1 KB

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