123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- package utils
- import (
- "crypto/md5"
- "crypto/rand"
- "encoding/hex"
- "io"
- "math"
- "math/big"
- "os"
- "reflect"
- "strings"
- "golang.org/x/exp/constraints"
- )
- // Concat 字符串拼接
- func Concat(strArr ...string) string {
- var builder strings.Builder
- for i := 0; i < len(strArr); i++ {
- builder.WriteString(strArr[i])
- }
- return builder.String()
- }
- // PageLimitOffset 根据分页页数和页大小得到Limit&Offset
- func PageLimitOffset(page int64, pageSize int64) (limit int64, offset int64) {
- limit = pageSize
- offset = pageSize * (page - 1)
- // 分页大小默认值
- if limit == 0 {
- limit = 10
- }
- return
- }
- // Ternary 三元运算
- func Ternary[T any](ifOp bool, trueV, falseV T) T {
- if ifOp {
- return trueV
- }
- return falseV
- }
- // InSlice 判断指定值是否在切片中
- func InSlice[T constraints.Ordered | reflect.Kind](needle T, haystack []T) bool {
- if len(haystack) == 0 {
- return false
- }
- for i := 0; i < len(haystack); i++ {
- if haystack[i] == needle {
- return true
- }
- }
- return false
- }
- // RandomExpire redis过期时间添加一个随机值
- func RandomExpire(timestamp int64, randSecond int64) int64 {
- return timestamp + Rand(0, randSecond)
- }
- // Rand 生成区间[-m, n]的安全随机数
- func Rand(min, max int64) int64 {
- if min > max {
- min, max = max, min
- }
- if min < 0 {
- i64Min := int64(math.Abs(float64(min)))
- result, _ := rand.Int(rand.Reader, big.NewInt(max+i64Min+1))
- return result.Int64() - i64Min
- } else {
- result, _ := rand.Int(rand.Reader, big.NewInt(max-min+1))
- return min + result.Int64()
- }
- }
- // SliceSum 切片求和
- func SliceSum[T constraints.Integer | constraints.Float](slice []T) (sum T) {
- for i := 0; i < len(slice); i++ {
- sum += slice[i]
- }
- return sum
- }
- // SliceColumn 结构体切片,数组切片,map切片中提取指定字段
- func SliceColumn[T, V any](slice []T, column string) []V {
- values := make([]V, len(slice))
- switch reflect.TypeOf(slice).Elem().Kind() {
- case reflect.Slice, reflect.Array:
- for i, v := range slice {
- values[i] = reflect.ValueOf(v).Index(int(reflect.ValueOf(column).Int())).Interface().(V)
- }
- case reflect.Map:
- for i, v := range slice {
- values[i] = reflect.ValueOf(v).MapIndex(reflect.ValueOf(column)).Interface().(V)
- }
- case reflect.Struct:
- for i, v := range slice {
- values[i] = StructColumnByTag[V](v, column, "json")
- }
- }
- return values
- }
- // SliceColumns 结构体切片,数组切片,map切片中提取指定多个字段, 以指定符号分割
- func SliceColumns[T any](slice []T, sep string, columns ...string) []string {
- values := make([]string, 0, len(slice))
- sCols := make([][]any, 0, len(columns))
- for _, column := range columns {
- sCols = append(sCols, SliceColumn[T, any](slice, column))
- }
- for i := range sCols[0] {
- elems := make([]any, 0, len(columns))
- for j := range columns {
- elems = append(elems, sCols[j][i])
- }
- values = append(values, Implode(elems, sep))
- }
- return values
- }
- func StructColumnByTag[V any](s any, column, tag string) (ret V) {
- val, typ := Indirect(s)
- if typ.Kind() != reflect.Struct {
- panic("expect struct")
- }
- for i := 0; i < typ.NumField(); i++ {
- typField := typ.Field(i)
- if typField.Anonymous && typField.Type.Kind() == reflect.Struct {
- return StructColumnByTag[V](val.Field(i).Interface(), column, tag)
- }
- tagName := typField.Tag.Get(tag)
- if tagName == column {
- return val.Field(i).Interface().(V)
- }
- }
- return ret
- }
- // SliceDelIdx 删除切片中指定索引
- func SliceDelIdx[T any](slice []T, idx ...int) []T {
- ret := make([]T, 0, len(slice))
- for i := 0; i < len(slice); i++ {
- if !InSlice(i, idx) {
- ret = append(ret, slice[i])
- }
- }
- return ret
- }
- // SliceDelVal 删除切片中指定值
- func SliceDelVal[T constraints.Ordered](slice []T, val ...T) []T {
- ret := make([]T, 0, len(slice))
- for i := 0; i < len(slice); i++ {
- if !InSlice(slice[i], val) {
- ret = append(ret, slice[i])
- }
- }
- return ret
- }
- // IsDir 判断路径是否存在且为文件夹
- func IsDir(path string) bool {
- stat, err := os.Stat(path)
- if err != nil {
- return false
- }
- return stat.IsDir()
- }
- // IsFile 判断路径是否存在且为文件
- func IsFile(path string) bool {
- stat, err := os.Stat(path)
- if err != nil {
- return false
- }
- return !stat.IsDir()
- }
- // FileMD5 计算文件的Md5
- func FileMD5(filePath string) (string, error) {
- file, err := os.Open(filePath)
- defer func() { _ = file.Close() }()
- if err != nil {
- return "", err
- }
- hash := md5.New()
- _, _ = io.Copy(hash, file)
- return hex.EncodeToString(hash.Sum(nil)), nil
- }
- // EqualSlice 切片是否相等
- func EqualSlice[T constraints.Ordered](s1, s2 []T) bool {
- if len(s1) != len(s2) {
- return false
- }
- if (s1 == nil) != (s2 == nil) {
- return false
- }
- for i := 0; i < len(s1); i++ {
- if s1[i] != s2[i] {
- return false
- }
- }
- return true
- }
- // IsComplexType 判断是否为复杂数据结构
- func IsComplexType(typ reflect.Type) bool {
- kind := typ.Kind()
- if !InSlice(kind, ComplexType) {
- return false
- }
- // []byte 不作为复杂类型
- if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() == reflect.Uint8 {
- return false
- }
- return true
- }
- // b=++a
- func IncrementAfter(inNum *int64, increStepOpt ...int64) int64 {
- var (
- outNum, increStep int64
- )
- increStep = int64(1)
- if len(increStepOpt) > 0 {
- increStep = increStepOpt[0]
- }
- *inNum += increStep
- outNum = *inNum
- return outNum
- }
- // b=a++
- func IncrementBefore(inNum *int64, increStepOpt ...int64) int64 {
- var (
- outNum, increStep int64
- )
- increStep = int64(1)
- if len(increStepOpt) > 0 {
- increStep = increStepOpt[0]
- }
- outNum = *inNum
- *inNum += increStep
- return outNum
- }
|