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的Cap,Len,以及数组的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 }