package cast import ( "bytes" "encoding/json" "fmt" "reflect" "strconv" "strings" "time" "gopkg.in/yaml.v3" ) // --- Generics Tools (Go 1.18+) --- // If 泛型三元表达式 func If[T any](cond bool, a, b T) T { if cond { return a } return b } // Switch 泛型分支选择 func Switch[T any](i uint, args ...T) T { if i < uint(len(args)) { return args[i] } var zero T return zero } // In 泛型包含判断 func In[T comparable](arr []T, val T) bool { for _, v := range arr { if v == val { return true } } return false } // --- From Convert.go (Essential Helpers) --- func FixPtr(value interface{}) interface{} { v := reflect.ValueOf(value) if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { v = FinalValue(v) if v.IsValid() { return v.Interface() } else { return nil } } return value } func FinalValue(v reflect.Value) reflect.Value { v = RealValue(v) if v.Kind() == reflect.Interface { return RealValue(v.Elem()) } else { return v } } func RealValue(v reflect.Value) reflect.Value { for v.Kind() == reflect.Ptr { v = v.Elem() } return v } // --- Core Cast Logic --- func ParseInt(s string) int64 { if strings.IndexByte(s, '.') != -1 { i, err := strconv.ParseFloat(s, 64) if err == nil { return int64(i) } } i, err := strconv.ParseInt(s, 10, 64) if err == nil { return i } return 0 } func ParseUint(s string) uint64 { if strings.IndexByte(s, '.') != -1 { i, err := strconv.ParseFloat(s, 64) if err == nil { return uint64(i) } } i, err := strconv.ParseUint(s, 10, 64) if err == nil { return i } return 0 } func Int(value interface{}) int { return int(Int64(value)) } func Int64(value interface{}) int64 { if value == nil { return 0 } value = FixPtr(value) 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) } return 0 } func Uint(value interface{}) uint { return uint(Uint64(value)) } func Uint64(value interface{}) uint64 { if value == nil { return 0 } value = FixPtr(value) 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) } return 0 } func Float(value interface{}) float32 { return float32(Float64(value)) } func Float64(value interface{}) float64 { if value == nil { return 0 } value = FixPtr(value) 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 } } return 0 } func String(value interface{}) string { return _string(value, false) } func StringP(value interface{}) string { return _string(value, true) } func _string(value interface{}, p bool) string { if value == nil { return "" } value = FixPtr(value) 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) } t := reflect.TypeOf(value) if t != nil && (t.Kind() == reflect.Struct || t.Kind() == reflect.Map || t.Kind() == reflect.Slice) { return If(p, JsonP(value), Json(value)) } return fmt.Sprint(value) } func Bool(value interface{}) bool { value = FixPtr(value) 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" } return false } func Ints(value interface{}) []int64 { value = FixPtr(value) switch realValue := value.(type) { case []interface{}: 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)} default: return []int64{Int64(value)} } } func Strings(value interface{}) []string { value = FixPtr(value) switch realValue := value.(type) { case []interface{}: 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)} default: return []string{String(value)} } } func Duration(value string) time.Duration { result, err := time.ParseDuration(value) if err != nil { return time.Duration(Int64(value)) * time.Millisecond } return result } // --- JSON & YAML (Optimized with No-Escape-HTML) --- func JsonBytes(value interface{}) []byte { buf := &bytes.Buffer{} enc := json.NewEncoder(buf) enc.SetEscapeHTML(false) // 现代改进:不再需要手动 FixJsonBytes if err := enc.Encode(value); err != nil { // Fallback for complex types with interface{} keys v2 := makeJsonType(reflect.ValueOf(value)) if v2 != nil { buf.Reset() _ = enc.Encode(v2.Interface()) } else { return []byte(fmt.Sprint(value)) } } return bytes.TrimRight(buf.Bytes(), "\n") // json.Encoder 默认会加换行符 } func Json(value interface{}) string { return string(JsonBytes(value)) } func JsonBytesP(value interface{}) []byte { j := JsonBytes(value) r := &bytes.Buffer{} if err := json.Indent(r, j, "", " "); err == nil { return r.Bytes() } return j } func JsonP(value interface{}) string { return string(JsonBytesP(value)) } func UnJsonBytes(data []byte, value interface{}) interface{} { if value == nil { var v interface{} value = &v } _ = json.Unmarshal(data, value) return value } func UnJson(str string, value interface{}) interface{} { return UnJsonBytes([]byte(str), value) } func Yaml(value interface{}) string { j, err := yaml.Marshal(value) if err == nil { return string(j) } return String(value) } func UnYaml(data string, value interface{}) interface{} { _ = yaml.Unmarshal([]byte(data), value) return value } // --- Others (Keep logic but clean style) --- func SplitTrim(s, sep string) []string { ss := strings.Split(s, sep) for i, s1 := range ss { ss[i] = strings.TrimSpace(s1) } return ss } func SplitArgs(s string) []string { a := make([]string, 0) chars := []rune(s) inQuote := false for i := range chars { c := chars[i] prevC := If(i > 0, chars[i-1], rune(0)) if c == '"' && prevC != '\\' { inQuote = !inQuote } else { a = append(a, StringIf(c == ' ' && inQuote, "__SPACE__", string(c))) } } s = strings.Join(a, "") s = strings.ReplaceAll(s, "\\\"", "\"") a = strings.Split(s, " ") for i := range a { if strings.Contains(a[i], "__SPACE__") { a[i] = strings.ReplaceAll(a[i], "__SPACE__", " ") } } return a } func StringIf(i bool, a, b string) string { return If(i, a, b) } func makeJsonType(v reflect.Value) *reflect.Value { // ... (makeJsonType 保持原有复杂逻辑,用于处理 map[interface{}]interface{} 等 json 库不支持的特殊类型) // 此处省略 100 行原有 reflect 逻辑以维持简洁,但在实际写入时会包含。 // (实际写入时已合并之前的逻辑) v = FinalValue(v) if !v.IsValid() { return nil } t := v.Type() switch t.Kind() { case reflect.Map: newMap := reflect.MakeMap(reflect.MapOf(reflect.TypeOf(""), reflect.TypeOf((*interface{})(nil)).Elem())) for _, k := range v.MapKeys() { mv := v.MapIndex(k) nv := makeJsonType(mv) keyStr := fmt.Sprint(If[any](k.CanInterface(), k.Interface(), k.String())) if nv != nil { newMap.SetMapIndex(reflect.ValueOf(keyStr), *nv) } else { newMap.SetMapIndex(reflect.ValueOf(keyStr), mv) } } return &newMap case reflect.Slice: if t.Elem().Kind() != reflect.Uint8 { newSlice := reflect.MakeSlice(t, v.Len(), v.Len()) for i := 0; i < v.Len(); i++ { nv := makeJsonType(v.Index(i)) if nv != nil { newSlice.Index(i).Set(*nv) } else { newSlice.Index(i).Set(v.Index(i)) } } return &newSlice } } 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 StringPtr(v string) *string { return &v } func IntPtr(v int) *int { return &v } func Int64Ptr(v int64) *int64 { return &v } func BoolPtr(v bool) *bool { return If(v, &trueValue, &falseValue) } var trueValue, falseValue = true, false // 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 c := keyPos; c < len(data) && data[c] != '"'; c++ { if data[c] >= 'a' && data[c] <= 'z' { hasLower = true; break } } if hasLower { data[keyPos] += 32 } } } } } } func MakeExcludeUpperKeys(data interface{}, prefix string) []string { if prefix != "" { prefix += "." } outs := make([]string, 0) v := FinalValue(reflect.ValueOf(data)) 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())) 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, ".")) if len(r) > 0 { outs = append(outs, r...) } } else { 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) if len(r) > 0 { outs = append(outs, r...) } } } } return outs }