package cast import ( "bytes" "encoding/json" "fmt" "reflect" "slices" "strconv" "strings" "time" ) // If 泛型三元表达式 func If[T any](condition bool, trueVal, falseVal T) T { if condition { return trueVal } return falseVal } // In 泛型包含判断 func In[T comparable](arr []T, val T) bool { return slices.Contains(arr, val) } // As 忽略错误,返回零值 (消除摩擦) func As[T any](v T, err error) T { if err != nil { var zero T return zero } return v } func RealValue(v reflect.Value) reflect.Value { for v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface { if v.IsNil() { return v } v = v.Elem() } return v } // --- Core Cast Logic --- var ( timeType = reflect.TypeOf(time.Time{}) ) // To 深度转换 (支持基础类型、Slice、Map、Struct 及 JSON 自动转换,零摩擦模式) func To[T any](v any) T { var res T performRecursiveTo(reflect.ValueOf(v), reflect.ValueOf(&res).Elem()) return res } // Convert 深度转换 (支持基础类型、Slice、Map、Struct 及 JSON 自动转换,原地更新) func Convert(dst, src any) { if dst == nil { return } dstV := reflect.ValueOf(dst) var srcV reflect.Value if v, ok := src.(reflect.Value); ok { srcV = v } else { srcV = reflect.ValueOf(src) } // Task 1: 拦截“自我转换”死循环陷阱 (Self-Assignment Guard) if dstV.Kind() == reflect.Pointer && srcV.Kind() == reflect.Pointer { if dstV.Pointer() == srcV.Pointer() { return } } performRecursiveTo(srcV, dstV) } func performRecursiveTo(src, dst reflect.Value) { // 0. 处理 Interface 目标 (直接赋值) if dst.Kind() == reflect.Interface { if dst.CanSet() { dst.Set(RealValue(src)) } return } // 1. 处理指针 (自动初始化与解引用) for dst.Kind() == reflect.Pointer { if dst.IsNil() { if dst.CanSet() { dst.Set(reflect.New(dst.Type().Elem())) } else { return } } dst = dst.Elem() } // 2. 解开源数据 src = RealValue(src) if !src.IsValid() { return } dstType := dst.Type() // 3. 处理 JSON Unmarshaler 接口 (优先级高) if dst.CanAddr() { if unmarshaler, ok := dst.Addr().Interface().(json.Unmarshaler); ok { var b []byte if src.Kind() == reflect.String { b = []byte(src.String()) } else if src.Kind() == reflect.Slice && src.Type().Elem().Kind() == reflect.Uint8 { b = src.Bytes() } else { b, _ = ToJSONBytes(src.Interface()) } if len(b) > 0 { _ = unmarshaler.UnmarshalJSON(b) return } } } // 4. Frictionless 增强:单值 <-> 切片 自动转换 if src.Kind() == reflect.Slice && src.Type().Elem().Kind() != reflect.Uint8 && src.Len() > 0 && dst.Kind() != reflect.Slice && dst.Kind() != reflect.Array && dst.Kind() != reflect.Map { src = RealValue(src.Index(0)) } // 5. 基础类型快速转换 (利用 cast 已有的高性能基础函数) switch dst.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if dst.CanSet() { dst.SetInt(Int64(src.Interface())) } return case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if dst.CanSet() { dst.SetUint(Uint64(src.Interface())) } return case reflect.Float32, reflect.Float64: if dst.CanSet() { dst.SetFloat(Float64(src.Interface())) } return case reflect.String: if dst.CanSet() { if isComplexValue(src.Interface()) { s, _ := ToJSON(src.Interface()) dst.SetString(s) } else { dst.SetString(String(src.Interface())) } } return case reflect.Bool: if dst.CanSet() { dst.SetBool(Bool(src.Interface())) } return } // 原生 time.Time 支持 if dstType == timeType { if dst.CanSet() { dst.Set(reflect.ValueOf(ToTime(src.Interface(), ""))) } return } // 6. 复杂容器深度递归转换 switch dst.Kind() { case reflect.Struct: if src.Kind() == reflect.Map { recursiveMapToStruct(src, dst) } else if src.Kind() == reflect.Struct { recursiveStructToStruct(src, dst) } else if src.Kind() == reflect.String || (src.Kind() == reflect.Slice && src.Type().Elem().Kind() == reflect.Uint8) { if dst.CanAddr() { _ = UnmarshalJSON(src.Interface(), dst.Addr().Interface()) } } case reflect.Map: if dst.IsNil() { if dst.CanSet() { dst.Set(reflect.MakeMap(dstType)) } else { return } } if src.Kind() == reflect.Map { recursiveMapToMap(src, dst) } else if src.Kind() == reflect.Struct { recursiveStructToMap(src, dst) } else if src.Kind() == reflect.Slice || src.Kind() == reflect.Array { recursiveSliceToMap(src, dst) } else if src.Kind() == reflect.String { if dst.CanAddr() { _ = UnmarshalJSON(src.Interface(), dst.Addr().Interface()) } } case reflect.Slice: if dstType.Elem().Kind() == reflect.Uint8 { if dst.CanSet() { if isComplexValue(src.Interface()) { b, _ := ToJSONBytes(src.Interface()) dst.SetBytes(b) } else { dst.SetBytes(toBytes(src.Interface())) } } } else { // JSON/CSV 字符串增强 if src.Kind() == reflect.String { s := src.String() if isJSONText(s) { if dst.CanAddr() { _ = UnmarshalJSON(s, dst.Addr().Interface()) return } } if !strings.HasPrefix(s, "[") && strings.Contains(s, ",") { src = reflect.ValueOf(Split(s, ",")) } } recursiveSliceToSlice(src, dst) } case reflect.Func: if src.Kind() == reflect.Func { dst.Set(reflect.MakeFunc(dstType, func(args []reflect.Value) []reflect.Value { srcType := src.Type() inParams := make([]reflect.Value, srcType.NumIn()) for i := 0; i < srcType.NumIn(); i++ { inParams[i] = reflect.New(srcType.In(i)).Elem() if i < len(args) { performRecursiveTo(args[i], inParams[i]) } } results := src.Call(inParams) outParams := make([]reflect.Value, dstType.NumOut()) for i := 0; i < dstType.NumOut(); i++ { outParams[i] = reflect.New(dstType.Out(i)).Elem() if i < len(results) { performRecursiveTo(results[i], outParams[i]) } } return outParams })) } } } // 内部递归助手 (零分配/高性能设计) func recursiveMapToStruct(src, dst reflect.Value) { if !dst.CanAddr() { return } dstAddr := dst.Addr() dstType := dst.Type() descriptor := getDecoderFieldMap(dstType) iter := src.MapRange() // 零分配遍历 for iter.Next() { rk := iter.Key() var key string if rk.Kind() == reflect.String { key = rk.String() } else { key = String(rk.Interface()) } if index, isTime, format, ok := matchField(key, descriptor); ok { field := dst.Field(index) fieldInfo := dstType.Field(index) // ParseHook 支持: ParseFieldName(sourceType) FieldType if method, ok := dstAddr.Type().MethodByName("Parse" + fieldInfo.Name); ok { arg := reflect.New(method.Type.In(1)).Elem() performRecursiveTo(iter.Value(), arg) res := method.Func.Call([]reflect.Value{dstAddr, arg}) field.Set(res[0]) continue } if isTime { field.Set(reflect.ValueOf(ToTime(iter.Value().Interface(), format))) } else { performRecursiveTo(iter.Value(), field) } } } } func recursiveStructToStruct(src, dst reflect.Value) { if !dst.CanAddr() { return } dstAddr := dst.Addr() srcType := src.Type() dstType := dst.Type() descriptor := getDecoderFieldMap(dstType) for i := 0; i < src.NumField(); i++ { field := srcType.Field(i) if !field.IsExported() { continue } if field.Anonymous { recursiveStructToStruct(src.Field(i), dst) continue } // 使用 matchField 实现归一化 Key 匹配 (零分配) if index, isTime, format, ok := matchField(field.Name, descriptor); ok { df := dst.Field(index) fieldInfo := dstType.Field(index) // ParseHook 支持 if method, ok := dstAddr.Type().MethodByName("Parse" + fieldInfo.Name); ok { arg := reflect.New(method.Type.In(1)).Elem() performRecursiveTo(src.Field(i), arg) res := method.Func.Call([]reflect.Value{dstAddr, arg}) df.Set(res[0]) continue } if isTime { df.Set(reflect.ValueOf(ToTime(src.Field(i).Interface(), format))) } else { performRecursiveTo(src.Field(i), df) } } } } func recursiveMapToMap(src, dst reflect.Value) { kt := dst.Type().Key() vt := dst.Type().Elem() newKey := reflect.New(kt).Elem() newVal := reflect.New(vt).Elem() iter := src.MapRange() for iter.Next() { newKey.Set(reflect.Zero(kt)) performRecursiveTo(iter.Key(), newKey) newVal.Set(reflect.Zero(vt)) performRecursiveTo(iter.Value(), newVal) dst.SetMapIndex(newKey, newVal) } } func recursiveStructToMap(src, dst reflect.Value) { kt := dst.Type().Key() vt := dst.Type().Elem() newKey := reflect.New(kt).Elem() newVal := reflect.New(vt).Elem() srcType := src.Type() for i := 0; i < src.NumField(); i++ { field := srcType.Field(i) if !field.IsExported() { continue } if field.Anonymous { recursiveStructToMap(src.Field(i), dst) continue } newKey.Set(reflect.Zero(kt)) performRecursiveTo(reflect.ValueOf(GetLowerName(field.Name)), newKey) newVal.Set(reflect.Zero(vt)) performRecursiveTo(src.Field(i), newVal) dst.SetMapIndex(newKey, newVal) } } func recursiveSliceToMap(src, dst reflect.Value) { kt := dst.Type().Key() vt := dst.Type().Elem() newKey := reflect.New(kt).Elem() newVal := reflect.New(vt).Elem() for i := 0; i < src.Len(); i += 2 { newKey.Set(reflect.Zero(kt)) performRecursiveTo(src.Index(i), newKey) newVal.Set(reflect.Zero(vt)) if i+1 < src.Len() { performRecursiveTo(src.Index(i+1), newVal) } dst.SetMapIndex(newKey, newVal) } } func recursiveSliceToSlice(src, dst reflect.Value) { et := dst.Type().Elem() temp := reflect.New(et).Elem() if src.Kind() == reflect.Slice || src.Kind() == reflect.Array { l := src.Len() dst.Set(reflect.MakeSlice(dst.Type(), l, l)) for i := 0; i < l; i++ { temp.Set(reflect.Zero(et)) performRecursiveTo(src.Index(i), temp) dst.Index(i).Set(temp) } } else { // Frictionless: 自动包装单值为切片 (覆盖赋值) dst.Set(reflect.MakeSlice(dst.Type(), 1, 1)) temp.Set(reflect.Zero(et)) performRecursiveTo(src, temp) dst.Index(0).Set(temp) } } func ToTime(v any, format string) time.Time { if v == nil { return time.Time{} } if t, ok := v.(time.Time); ok { return t.In(DefaultTimeZone.loc) } if format != "" { s := String(v) if t, err := time.ParseInLocation(format, s, DefaultTimeZone.loc); err == nil { return t } } return DefaultTimeZone.ParseTime(v) } func reflectCast(value any, t reflect.Type) reflect.Value { var v reflect.Value if t.Kind() == reflect.Ptr { v = reflect.New(t.Elem()) } else { v = reflect.New(t).Elem() } performRecursiveTo(reflect.ValueOf(value), v) return v } func reflectCastE(value any, t reflect.Type) (reflect.Value, error) { return reflectCast(value, t), nil } func ToInt64E(v any) (int64, error) { return Int64(v), nil } func ToUint64E(v any) (uint64, error) { return Uint64(v), nil } func ToFloat64E(v any) (float64, error) { return Float64(v), nil } func isJSONText(v any) bool { switch val := v.(type) { case string: s := strings.TrimSpace(val) return strings.HasPrefix(s, "{") || strings.HasPrefix(s, "[") case []byte: s := bytes.TrimSpace(val) return bytes.HasPrefix(s, []byte("{")) || bytes.HasPrefix(s, []byte("[")) } return false } func isComplexType(t reflect.Type) bool { kind := t.Kind() for kind == reflect.Ptr { t = t.Elem() kind = t.Kind() } return kind == reflect.Struct || kind == reflect.Map || (kind == reflect.Slice && t.Elem().Kind() != reflect.Uint8) } func isComplexValue(v any) bool { if v == nil { return true } rv := RealValue(reflect.ValueOf(v)) if !rv.IsValid() || rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface { return true } kind := rv.Kind() return kind == reflect.Struct || kind == reflect.Map || (kind == reflect.Slice && rv.Type().Elem().Kind() != reflect.Uint8) } func parseInt(s string) int64 { i, err := strconv.ParseInt(s, 10, 64) if err == nil { return i } if f, err := strconv.ParseFloat(s, 64); err == nil { return int64(f) } return 0 } func parseUint(s string) uint64 { i, err := strconv.ParseUint(s, 10, 64) if err == nil { return i } if f, err := strconv.ParseFloat(s, 64); err == nil { return uint64(f) } return 0 } func Int(value any) int { return int(Int64(value)) } // Helper for integer coercion to avoid repetition func toInt64(value any) (int64, bool) { switch v := value.(type) { case int: return int64(v), true case int8: return int64(v), true case int16: return int64(v), true case int32: return int64(v), true case int64: return v, true case uint: return int64(v), true case uint8: return int64(v), true case uint16: return int64(v), true case uint32: return int64(v), true case uint64: return int64(v), true case float32: return int64(v), true case float64: return int64(v), true case bool: return If(v, int64(1), int64(0)), true } return 0, false } func Int64(value any) int64 { if value == nil { return 0 } if i, ok := toInt64(value); ok { return i } switch realValue := value.(type) { case []byte: return parseInt(string(realValue)) case string: return parseInt(realValue) } rv := reflect.ValueOf(value) if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface { if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer { return Int64(rv.Interface()) } } return 0 } func Uint(value any) uint { return uint(Uint64(value)) } func Uint64(value any) uint64 { if value == nil { return 0 } switch realValue := value.(type) { case int: return uint64(realValue) case int8: return uint64(realValue) case int16: return uint64(realValue) case int32: return uint64(realValue) case int64: return uint64(realValue) case uint: return uint64(realValue) case uint8: return uint64(realValue) case uint16: return uint64(realValue) case uint32: return uint64(realValue) case uint64: return realValue case float32: return uint64(realValue) case float64: return uint64(realValue) case bool: return If(realValue, uint64(1), uint64(0)) case []byte: return parseUint(string(realValue)) case string: return parseUint(realValue) } rv := reflect.ValueOf(value) if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface { if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer { return Uint64(rv.Interface()) } } return 0 } func Float(value any) float32 { return float32(Float64(value)) } func Float64(value any) float64 { if value == nil { return 0 } switch realValue := value.(type) { case int, int8, int16, int32, int64: return float64(Int64(realValue)) case uint, uint8, uint16, uint32, uint64: return float64(Uint64(realValue)) case float32: return float64(realValue) case float64: return realValue case bool: return If(realValue, 1.0, 0.0) case []byte: i, err := strconv.ParseFloat(string(realValue), 64) if err == nil { return i } case string: i, err := strconv.ParseFloat(realValue, 64) if err == nil { return i } } rv := reflect.ValueOf(value) if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface { if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer { return Float64(rv.Interface()) } } return 0 } func String(value any) string { if value == nil { return "" } switch realValue := value.(type) { case int, int8, int16, int32, int64: return strconv.FormatInt(Int64(realValue), 10) case uint, uint8, uint16, uint32, uint64: return strconv.FormatUint(Uint64(realValue), 10) case float32: return strconv.FormatFloat(float64(realValue), 'f', -1, 32) case float64: return strconv.FormatFloat(realValue, 'f', -1, 64) case bool: return If(realValue, "true", "false") case string: return realValue case []byte: return string(realValue) } rv := reflect.ValueOf(value) if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface { if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer { return String(rv.Interface()) } } return fmt.Sprint(value) } func Bool(value any) bool { if value == nil { return false } if b, ok := value.(bool); ok { return b } if i, ok := toInt64(value); ok { return i != 0 } switch realValue := value.(type) { case []byte: s := strings.ToLower(string(realValue)) return s == "1" || s == "t" || s == "true" case string: s := strings.ToLower(realValue) return s == "1" || s == "t" || s == "true" } rv := reflect.ValueOf(value) if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface { if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer { return Bool(rv.Interface()) } } return false } func Duration(value any) time.Duration { if value == nil { return 0 } switch realValue := value.(type) { case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: return time.Duration(Int64(realValue)) case float32, float64: return time.Duration(Float64(realValue) * float64(time.Second)) case []byte, string: if result, err := time.ParseDuration(String(realValue)); err == nil { return result } } rv := reflect.ValueOf(value) if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface { if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer { return Duration(rv.Interface()) } } return 0 } func ToJSONBytes(value any) ([]byte, error) { return fastToJSONBytes(value) } func ToJSONDesensitizeBytes(value any, keys []string) ([]byte, error) { return fastToJSONBytes(value, keys...) } func ToJSON(value any) (string, error) { b, err := ToJSONBytes(value) return string(b), err } func PrettyToJSON(value any) string { j := As(ToJSONBytes(value)) r := &bytes.Buffer{} if err := json.Indent(r, j, "", " "); err == nil { return r.String() } return string(j) } func toBytes(data any) []byte { if data == nil { return nil } switch v := data.(type) { case []byte: return v case string: return []byte(v) } return []byte(String(data)) } func UnmarshalJSON(data any, value any) error { b := toBytes(data) if b == nil { return fmt.Errorf("nil data") } return fastUnmarshalJSONBytes(b, value) } func FromJSON[T any](data any) (T, error) { var v T err := UnmarshalJSON(data, &v) return v, err } // --- Others (Keep logic but clean style) --- func Split(s, sep string) []string { ss := strings.Split(s, sep) out := make([]string, 0, len(ss)) for _, s1 := range ss { if s2 := strings.TrimSpace(s1); s2 != "" { out = append(out, s2) } } return out } func SplitArgs(s string) []string { var res []string var builder strings.Builder inQuote := false escaped := false chars := []rune(s) for i := 0; i < len(chars); i++ { c := chars[i] if escaped { builder.WriteRune(c) escaped = false continue } if c == '\\' { escaped = true continue } if c == '"' { inQuote = !inQuote continue } if c == ' ' && !inQuote { if builder.Len() > 0 { res = append(res, builder.String()) builder.Reset() } continue } builder.WriteRune(c) } if builder.Len() > 0 { res = append(res, builder.String()) } return res } func JoinArgs(arr []string, sep string) string { var builder strings.Builder for i, s := range arr { if i > 0 { builder.WriteString(sep) } // 如果包含空格或引号,则需要包裹引号并转义内部引号 if strings.ContainsRune(s, ' ') || strings.ContainsRune(s, '"') { builder.WriteByte('"') builder.WriteString(strings.ReplaceAll(s, "\"", "\\\"")) builder.WriteByte('"') } else { builder.WriteString(s) } } return builder.String() } func UniqueAppend(to []string, from ...any) []string { exists := make(map[string]struct{}, len(to)) for _, s := range to { exists[s] = struct{}{} } for _, a := range from { s := String(a) if _, ok := exists[s]; !ok { to = append(to, s) exists[s] = struct{}{} } } return to } func ArrayToBoolMap[T comparable](arr []T) map[T]bool { r := map[T]bool{} for _, s := range arr { r[s] = true } return r } // ToMap 泛型构建新 Map func ToMap[K comparable, V any](source any) (map[K]V, error) { m := make(map[K]V) performRecursiveTo(reflect.ValueOf(source), reflect.ValueOf(m)) return m, nil } // ToSlice 泛型构建新 Slice func ToSlice[T any](source any) ([]T, error) { var s []T performRecursiveTo(reflect.ValueOf(source), reflect.ValueOf(&s).Elem()) return s, nil } // FillMap 将 source 填充到目标 map 中 func FillMap(target any, source any) { Convert(target, source) } // FillSlice 将 source 填充到目标 slice 中 func FillSlice(target any, source any) { Convert(target, source) } // 补充缺失的 Key 转换工具 func GetLowerName(s string) string { if len(s) > 0 && s[0] >= 'A' && s[0] <= 'Z' { hasLower := false for i := 0; i < len(s); i++ { if s[i] >= 'a' && s[i] <= 'z' { hasLower = true break } } if hasLower { return strings.ToLower(s[:1]) + s[1:] } } return s } func GetUpperName(s string) string { if s == "" { return "" } return strings.ToUpper(s[:1]) + s[1:] } // 指针工具 func Ptr[T any](v T) *T { return &v } // FixUpperCase (保留以支持历史复杂的 Key 转换需求) func FixUpperCase(data []byte, excludesKeys []string) { // 原有逻辑保持 n := len(data) types, keys, tpos := make([]bool, 0), make([]string, 0), -1 for i := 0; i < n-1; i++ { if tpos+1 >= len(types) { types = append(types, false) keys = append(keys, "") } switch data[i] { case '{': tpos++ types[tpos] = true keys[tpos] = "" case '}': tpos-- case '[': tpos++ types[tpos] = false keys[tpos] = "" case ']': tpos-- case '"': keyPos := -1 if i > 0 && (data[i-1] == '{' || (data[i-1] == ',' && tpos >= 0 && types[tpos])) { keyPos = i + 1 } i++ for ; i < n-1; i++ { if data[i] == '\\' { i++ continue } if data[i] == '"' { if keyPos >= 0 && len(excludesKeys) > 0 { keys[tpos] = string(data[keyPos:i]) } break } } if keyPos >= 0 && (data[keyPos] >= 'A' && data[keyPos] <= 'Z') { excluded := false if len(excludesKeys) > 0 { checkStr := strings.Join(keys[0:tpos+1], ".") for _, ek := range excludesKeys { if strings.HasSuffix(ek, ".") { excluded = strings.HasPrefix(checkStr, ek) } else { excluded = checkStr == ek } if excluded { break } } } if !excluded { hasLower := false for _, b := range data[keyPos:i] { if b >= 'a' && b <= 'z' { hasLower = true break } } if hasLower { data[keyPos] |= 0x20 } } } } } }