package cast import ( "bytes" "encoding/json" "fmt" "reflect" "slices" "strconv" "strings" "time" "gopkg.in/yaml.v3" ) // 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) } 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 --- 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)) } func Int64(value any) int64 { if value == nil { return 0 } switch realValue := value.(type) { case int: return int64(realValue) case int8: return int64(realValue) case int16: return int64(realValue) case int32: return int64(realValue) case int64: return realValue case uint: return int64(realValue) case uint8: return int64(realValue) case uint16: return int64(realValue) case uint32: return int64(realValue) case uint64: return int64(realValue) case float32: return int64(realValue) case float64: return int64(realValue) case bool: return If(realValue, int64(1), int64(0)) 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 { switch realValue := value.(type) { case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64: return Uint64(realValue) != 0 case bool: return realValue 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 Ints(value any) []int64 { switch realValue := value.(type) { case []any: result := make([]int64, len(realValue)) for i, v := range realValue { result[i] = Int64(v) } return result case string: if strings.HasPrefix(realValue, "[") { result := make([]int64, 0) UnJson(realValue, &result) return result } return []int64{Int64(value)} } 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 Ints(rv.Interface()) } } return []int64{Int64(value)} } func Strings(value any) []string { switch realValue := value.(type) { case []any: result := make([]string, len(realValue)) for i, v := range realValue { result[i] = String(v) } return result case string: if strings.HasPrefix(realValue, "[") { result := make([]string, 0) UnJson(realValue, &result) return result } return []string{String(value)} } 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 Strings(rv.Interface()) } } return []string{String(value)} } 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) { buf := &bytes.Buffer{} enc := json.NewEncoder(buf) enc.SetEscapeHTML(false) // 现代改进:不再需要手动 FixJsonBytes if err := enc.Encode(value); err != nil { v2 := makeJsonType(reflect.ValueOf(value)) if v2 != nil { buf.Reset() err = enc.Encode(v2.Interface()) if err != nil { return nil, err } } else { return nil, err } } bytesResult := bytes.TrimRight(buf.Bytes(), "\n") excludeKeys := makeExcludeUpperKeys(value, "", 0) if len(bytesResult) == 4 && string(bytesResult) == "null" { t := reflect.TypeOf(bytesResult) if t.Kind() == reflect.Slice { bytesResult = []byte("[]") } if t.Kind() == reflect.Map { bytesResult = []byte("{}") } } FixUpperCase(bytesResult, excludeKeys) return bytesResult, nil } func MustJsonBytes(value any) []byte { j, err := ToJsonBytes(value) if err != nil { return []byte{} } return j } func ToJson(value any) (string, error) { j, err := ToJsonBytes(value) if err != nil { return "", err } return string(j), nil } func MustToJson(value any) string { return string(MustJsonBytes(value)) } func PrettyToJsonBytes(value any) []byte { j := MustJsonBytes(value) r := &bytes.Buffer{} if err := json.Indent(r, j, "", " "); err == nil { return r.Bytes() } return j } func PrettyToJson(value any) string { return string(PrettyToJsonBytes(value)) } func UnJsonBytes(data []byte, value any) (any, error) { if value == nil { var v any value = &v } err := json.Unmarshal(data, value) return value, err } func MustUnJsonBytes(data []byte, value any) any { v, err := UnJsonBytes(data, value) if err != nil { return nil } return v } func UnJson(str string, value any) (any, error) { return UnJsonBytes([]byte(str), value) } func MustUnJson(str string, value any) any { return MustUnJsonBytes([]byte(str), value) } func ToYaml(value any) (string, error) { j, err := YamlBytes(value) if err != nil { return "", err } return string(j), nil } func MustToYaml(value any) string { return string(MustYamlBytes(value)) } func UnYaml(data string, value any) (any, error) { return UnYamlBytes([]byte(data), value) } func MustUnYaml(data string, value any) any { return MustUnYamlBytes([]byte(data), value) } func YamlBytes(value any) ([]byte, error) { j, err := yaml.Marshal(value) if err == nil { return j, nil } return []byte(fmt.Sprint(value)), err } func MustYamlBytes(value any) []byte { j, err := YamlBytes(value) if err != nil { return []byte{} } return j } func UnYamlBytes(data []byte, value any) (any, error) { err := yaml.Unmarshal(data, value) return value, err } func MustUnYamlBytes(data []byte, value any) any { v, err := UnYamlBytes(data, value) if err != nil { return nil } return v } // --- 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 } func makeJsonType(inValue reflect.Value) *reflect.Value { if inValue.Kind() == reflect.Interface { inValue = inValue.Elem() } for inValue.Kind() == reflect.Ptr { inValue = inValue.Elem() } if !inValue.IsValid() { return nil } inType := inValue.Type() switch inType.Kind() { case reflect.Map: if inType.Key().Kind() == reflect.Interface { // 测试是否为数组 isMap := false length := inValue.Len() // 数组必须从 0 开始且连续 for i := range length { // 依次尝试 int, float64, string 三种可能的 Key 类型 if inValue.MapIndex(reflect.ValueOf(i)).Kind() == reflect.Invalid && inValue.MapIndex(reflect.ValueOf(float64(i))).Kind() == reflect.Invalid && inValue.MapIndex(reflect.ValueOf(strconv.Itoa(i))).Kind() == reflect.Invalid { isMap = true break } } if isMap { // 处理字典 newMap := reflect.MakeMap(reflect.MapOf(reflect.TypeFor[string](), inType.Elem())) for _, k := range inValue.MapKeys() { v1 := inValue.MapIndex(k) v2 := makeJsonType(v1) var k2 reflect.Value if k.CanInterface() { k2 = reflect.ValueOf(String(k.Interface())) } else { k2 = reflect.ValueOf(k.String()) } if v2 != nil { newMap.SetMapIndex(k2, *v2) } else { newMap.SetMapIndex(k2, v1) } } return &newMap } else { // 处理数组:按数字 Key 填入对应的 Index newArray := reflect.MakeSlice(reflect.SliceOf(inType.Elem()), length, length) for _, k := range inValue.MapKeys() { v1 := inValue.MapIndex(k) v2 := makeJsonType(v1) idx := int(Int64(k.Interface())) // 统一转为 int if idx >= 0 && idx < length { if v2 != nil { newArray.Index(idx).Set(*v2) } else { newArray.Index(idx).Set(v1) } } } return &newArray } } else { for _, k := range inValue.MapKeys() { v := makeJsonType(inValue.MapIndex(k)) if v != nil { inValue.SetMapIndex(k, *v) } } return nil } case reflect.Slice: if inType.Elem().Kind() != reflect.Uint8 { for i := inValue.Len() - 1; i >= 0; i-- { v := makeJsonType(inValue.Index(i)) if v != nil && inValue.Index(i).CanSet() { inValue.Index(i).Set(*v) } } } return nil case reflect.Struct: for i := inType.NumField() - 1; i >= 0; i-- { f := inType.Field(i) if f.Anonymous { v := makeJsonType(inValue.Field(i)) if v != nil && inValue.Field(i).CanSet() { inValue.Field(i).Set(*v) } } else { if f.Name[0] >= 65 && f.Name[0] <= 90 { v := makeJsonType(inValue.Field(i)) if v != nil && inValue.Field(i).CanSet() { inValue.Field(i).Set(*v) } } } } return nil default: return nil } } // 补充缺失的 Key 转换工具 func GetLowerName(s string) string { if s == "" { return "" } return strings.ToLower(s[:1]) + s[1:] } 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 } } } } } } func makeExcludeUpperKeys(data any, prefix string, level int) []string { if level > 100 { return nil } if prefix != "" { prefix += "." } outs := make([]string, 0) var v reflect.Value if rv, ok := data.(reflect.Value); ok { v = rv } else { v = reflect.ValueOf(data) } v = RealValue(v) if !v.IsValid() { return nil } t := v.Type() switch t.Kind() { case reflect.Map: for _, k := range v.MapKeys() { r := makeExcludeUpperKeys(v.MapIndex(k), prefix+fmt.Sprint(k.Interface()), level+1) if len(r) > 0 { outs = append(outs, r...) } } case reflect.Struct: for i := 0; i < t.NumField(); i++ { f := t.Field(i) if f.Anonymous { r := makeExcludeUpperKeys(v.Field(i), strings.TrimSuffix(prefix, "."), level+1) if len(r) > 0 { outs = append(outs, r...) } } else if f.IsExported() { tag := string(f.Tag) if strings.Contains(tag, "keepKey") { outs = append(outs, prefix+f.Name) } if strings.Contains(tag, "keepSubKey") { outs = append(outs, prefix+f.Name+".") } r := makeExcludeUpperKeys(v.Field(i), prefix+f.Name, level+1) if len(r) > 0 { outs = append(outs, r...) } } } } return outs }