utils/utils.go
2024-05-09 10:59:14 +08:00

176 lines
3.4 KiB
Go
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package utils
import (
"fmt"
"os"
"path/filepath"
"reflect"
"strings"
"unsafe"
"github.com/spf13/cast"
)
func GetFieldValue(i any, k string) any {
v := reflect.ValueOf(i)
var kv reflect.Value
if v.Kind() == reflect.Ptr {
v = reflect.Indirect(v)
}
if v.Kind() == reflect.Struct {
kv = v.FieldByName(k)
} else if v.Kind() == reflect.Map {
for _, key := range v.MapKeys() {
if key.String() == k {
kv = v.MapIndex(key)
}
}
}
switch kv.Kind() {
case reflect.String:
return kv.String()
case reflect.Bool:
return kv.Bool()
case reflect.Float32, reflect.Float64:
return kv.Float()
case reflect.Int, reflect.Int64:
return int(kv.Int())
case reflect.Invalid:
return nil
}
return kv.Interface()
}
func GetStructField(item any, key string) (field reflect.StructField, ok bool) {
vItem := reflect.TypeOf(item)
if vItem.Kind() == reflect.Ptr {
vItem = vItem.Elem()
}
if vItem.Kind() != reflect.Struct {
return field, false
}
return vItem.FieldByName(UcFirst(key))
}
func InterfaceToSlice(i any) (ret []any) {
rv := reflect.ValueOf(i)
if rv.Kind() == reflect.Ptr {
rv = reflect.Indirect(rv)
}
if rv.Kind() != reflect.Slice {
panic("请传入切片类型数据")
}
for i := 0; i < rv.Len(); i++ {
ret = append(ret, rv.Index(i).Interface())
}
return ret
}
func SliceConvert(origSlice any, newSliceType reflect.Type) any {
sv := reflect.ValueOf(origSlice)
if sv.Kind() != reflect.Slice {
panic(fmt.Sprintf("无效切片类型 %T (来源)", origSlice))
}
if newSliceType.Kind() != reflect.Slice {
panic(fmt.Sprintf("无效切片类型 %T (目标)", newSliceType))
}
// 生成新类型的切片
newSlice := reflect.New(newSliceType)
// hdr指向到新生成切片的SliceHeader
hdr := (*reflect.SliceHeader)(unsafe.Pointer(newSlice.Pointer()))
var newElemSize = int(sv.Type().Elem().Size()) / int(newSliceType.Elem().Size())
// 设置SliceHeader的CapLen以及数组的ptr
hdr.Cap = sv.Cap() * newElemSize
hdr.Len = sv.Len() * newElemSize
hdr.Data = uintptr(sv.Pointer())
return newSlice.Elem().Interface()
}
func DeepSearch(m map[string]any, path []string) map[string]any {
for _, k := range path {
m2, ok := m[k]
if !ok {
// intermediate key does not exist
// => create it and continue from there
m3 := make(map[string]interface{})
m[k] = m3
m = m3
continue
}
m3, ok := m2.(map[string]interface{})
if !ok {
// intermediate key is a value
// => replace with a new map
m3 = make(map[string]interface{})
m[k] = m3
}
// continue search from here
m = m3
}
return m
}
func MergeMap(shadow map[string]any, m map[string]any) map[string]any {
if shadow == nil {
shadow = make(map[string]any)
}
var m2 map[string]any
for k, val := range m {
switch val.(type) {
case map[string]any:
m2 = val.(map[string]any)
case map[any]any:
m2 = cast.ToStringMap(val)
default:
// immediate value
shadow[k] = val
continue
}
// recursively merge to shadow map
shadow[k] = MergeMap(cast.ToStringMap(shadow[k]), m2)
}
return shadow
}
func UcFirst(s string) string {
if s == "" {
return ""
}
return strings.ToUpper(s[:1]) + s[1:]
}
func StudlyCase(s string) string {
return strings.Replace(strings.Title(strings.Replace(s, "-", " ", -1)), " ", "", -1)
}
func GetAbsPath(s string) string {
if strings.HasPrefix(s, "/") {
return s
} else if dir, err := os.Getwd(); err == nil {
return filepath.Join(dir, s)
}
return s
}