common_func.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. package utils
  2. import (
  3. "crypto/md5"
  4. "crypto/rand"
  5. "encoding/hex"
  6. "io"
  7. "math"
  8. "math/big"
  9. "os"
  10. "reflect"
  11. "strings"
  12. "golang.org/x/exp/constraints"
  13. )
  14. // Concat 字符串拼接
  15. func Concat(strArr ...string) string {
  16. var builder strings.Builder
  17. for i := 0; i < len(strArr); i++ {
  18. builder.WriteString(strArr[i])
  19. }
  20. return builder.String()
  21. }
  22. // PageLimitOffset 根据分页页数和页大小得到Limit&Offset
  23. func PageLimitOffset(page int64, pageSize int64) (limit int64, offset int64) {
  24. limit = pageSize
  25. offset = pageSize * (page - 1)
  26. // 分页大小默认值
  27. if limit == 0 {
  28. limit = 10
  29. }
  30. return
  31. }
  32. // Ternary 三元运算
  33. func Ternary[T any](ifOp bool, trueV, falseV T) T {
  34. if ifOp {
  35. return trueV
  36. }
  37. return falseV
  38. }
  39. // InSlice 判断指定值是否在切片中
  40. func InSlice[T constraints.Ordered | reflect.Kind](needle T, haystack []T) bool {
  41. if len(haystack) == 0 {
  42. return false
  43. }
  44. for i := 0; i < len(haystack); i++ {
  45. if haystack[i] == needle {
  46. return true
  47. }
  48. }
  49. return false
  50. }
  51. // RandomExpire redis过期时间添加一个随机值
  52. func RandomExpire(timestamp int64, randSecond int64) int64 {
  53. return timestamp + Rand(0, randSecond)
  54. }
  55. // Rand 生成区间[-m, n]的安全随机数
  56. func Rand(min, max int64) int64 {
  57. if min > max {
  58. min, max = max, min
  59. }
  60. if min < 0 {
  61. i64Min := int64(math.Abs(float64(min)))
  62. result, _ := rand.Int(rand.Reader, big.NewInt(max+i64Min+1))
  63. return result.Int64() - i64Min
  64. } else {
  65. result, _ := rand.Int(rand.Reader, big.NewInt(max-min+1))
  66. return min + result.Int64()
  67. }
  68. }
  69. // SliceSum 切片求和
  70. func SliceSum[T constraints.Integer | constraints.Float](slice []T) (sum T) {
  71. for i := 0; i < len(slice); i++ {
  72. sum += slice[i]
  73. }
  74. return sum
  75. }
  76. // SliceColumn 结构体切片,数组切片,map切片中提取指定字段
  77. func SliceColumn[T, V any](slice []T, column string) []V {
  78. values := make([]V, len(slice))
  79. switch reflect.TypeOf(slice).Elem().Kind() {
  80. case reflect.Slice, reflect.Array:
  81. for i, v := range slice {
  82. values[i] = reflect.ValueOf(v).Index(int(reflect.ValueOf(column).Int())).Interface().(V)
  83. }
  84. case reflect.Map:
  85. for i, v := range slice {
  86. values[i] = reflect.ValueOf(v).MapIndex(reflect.ValueOf(column)).Interface().(V)
  87. }
  88. case reflect.Struct:
  89. for i, v := range slice {
  90. values[i] = StructColumnByTag[V](v, column, "json")
  91. }
  92. }
  93. return values
  94. }
  95. // SliceColumns 结构体切片,数组切片,map切片中提取指定多个字段, 以指定符号分割
  96. func SliceColumns[T any](slice []T, sep string, columns ...string) []string {
  97. values := make([]string, 0, len(slice))
  98. sCols := make([][]any, 0, len(columns))
  99. for _, column := range columns {
  100. sCols = append(sCols, SliceColumn[T, any](slice, column))
  101. }
  102. for i := range sCols[0] {
  103. elems := make([]any, 0, len(columns))
  104. for j := range columns {
  105. elems = append(elems, sCols[j][i])
  106. }
  107. values = append(values, Implode(elems, sep))
  108. }
  109. return values
  110. }
  111. func StructColumnByTag[V any](s any, column, tag string) (ret V) {
  112. val, typ := Indirect(s)
  113. if typ.Kind() != reflect.Struct {
  114. panic("expect struct")
  115. }
  116. for i := 0; i < typ.NumField(); i++ {
  117. typField := typ.Field(i)
  118. if typField.Anonymous && typField.Type.Kind() == reflect.Struct {
  119. return StructColumnByTag[V](val.Field(i).Interface(), column, tag)
  120. }
  121. tagName := typField.Tag.Get(tag)
  122. if tagName == column {
  123. return val.Field(i).Interface().(V)
  124. }
  125. }
  126. return ret
  127. }
  128. // SliceDelIdx 删除切片中指定索引
  129. func SliceDelIdx[T any](slice []T, idx ...int) []T {
  130. ret := make([]T, 0, len(slice))
  131. for i := 0; i < len(slice); i++ {
  132. if !InSlice(i, idx) {
  133. ret = append(ret, slice[i])
  134. }
  135. }
  136. return ret
  137. }
  138. // SliceDelVal 删除切片中指定值
  139. func SliceDelVal[T constraints.Ordered](slice []T, val ...T) []T {
  140. ret := make([]T, 0, len(slice))
  141. for i := 0; i < len(slice); i++ {
  142. if !InSlice(slice[i], val) {
  143. ret = append(ret, slice[i])
  144. }
  145. }
  146. return ret
  147. }
  148. // IsDir 判断路径是否存在且为文件夹
  149. func IsDir(path string) bool {
  150. stat, err := os.Stat(path)
  151. if err != nil {
  152. return false
  153. }
  154. return stat.IsDir()
  155. }
  156. // IsFile 判断路径是否存在且为文件
  157. func IsFile(path string) bool {
  158. stat, err := os.Stat(path)
  159. if err != nil {
  160. return false
  161. }
  162. return !stat.IsDir()
  163. }
  164. // FileMD5 计算文件的Md5
  165. func FileMD5(filePath string) (string, error) {
  166. file, err := os.Open(filePath)
  167. defer func() { _ = file.Close() }()
  168. if err != nil {
  169. return "", err
  170. }
  171. hash := md5.New()
  172. _, _ = io.Copy(hash, file)
  173. return hex.EncodeToString(hash.Sum(nil)), nil
  174. }
  175. // EqualSlice 切片是否相等
  176. func EqualSlice[T constraints.Ordered](s1, s2 []T) bool {
  177. if len(s1) != len(s2) {
  178. return false
  179. }
  180. if (s1 == nil) != (s2 == nil) {
  181. return false
  182. }
  183. for i := 0; i < len(s1); i++ {
  184. if s1[i] != s2[i] {
  185. return false
  186. }
  187. }
  188. return true
  189. }
  190. // IsComplexType 判断是否为复杂数据结构
  191. func IsComplexType(typ reflect.Type) bool {
  192. kind := typ.Kind()
  193. if !InSlice(kind, ComplexType) {
  194. return false
  195. }
  196. // []byte 不作为复杂类型
  197. if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() == reflect.Uint8 {
  198. return false
  199. }
  200. return true
  201. }
  202. // b=++a
  203. func IncrementAfter(inNum *int64, increStepOpt ...int64) int64 {
  204. var (
  205. outNum, increStep int64
  206. )
  207. increStep = int64(1)
  208. if len(increStepOpt) > 0 {
  209. increStep = increStepOpt[0]
  210. }
  211. *inNum += increStep
  212. outNum = *inNum
  213. return outNum
  214. }
  215. // b=a++
  216. func IncrementBefore(inNum *int64, increStepOpt ...int64) int64 {
  217. var (
  218. outNum, increStep int64
  219. )
  220. increStep = int64(1)
  221. if len(increStepOpt) > 0 {
  222. increStep = increStepOpt[0]
  223. }
  224. outNum = *inNum
  225. *inNum += increStep
  226. return outNum
  227. }