package reflux import ( "fmt" "reflect" "strconv" "strings" "unicode" "git.fsdpf.net/go/reflux/valuex" ) // DeepClone 深度克隆一个 reflect.Value func DeepClone(v reflect.Value) reflect.Value { // 解引用指针和接口以获取实际值 for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { if v.IsNil() { return reflect.Value{} } v = v.Elem() } if !v.IsValid() { return reflect.Value{} } // 创建新值的指针以便修改 cloned := reflect.New(v.Type()) CloneValue(cloned.Elem(), v) return cloned } // CloneValue 递归克隆值 func CloneValue(dst, src reflect.Value) { if !src.IsValid() { return } switch src.Kind() { case reflect.Ptr: if src.IsNil() { return } dst.Set(reflect.New(src.Type().Elem())) CloneValue(dst.Elem(), src.Elem()) case reflect.Interface: if src.IsNil() { return } cloned := DeepClone(src.Elem()) if cloned.IsValid() { dst.Set(cloned) } case reflect.Struct: for i := 0; i < src.NumField(); i++ { if dst.Field(i).CanSet() { CloneValue(dst.Field(i), src.Field(i)) } } case reflect.Slice: if src.IsNil() { return } dst.Set(reflect.MakeSlice(src.Type(), src.Len(), src.Cap())) cloneSequence(dst, src) case reflect.Array: cloneSequence(dst, src) case reflect.Map: if src.IsNil() { return } dst.Set(reflect.MakeMap(src.Type())) for _, key := range src.MapKeys() { val := src.MapIndex(key) clonedVal := cloneElement(val) dst.SetMapIndex(key, clonedVal) } default: // 对于基本类型(int, string, bool, float等),直接赋值 if dst.CanSet() { dst.Set(src) } } } // cloneSequence 克隆序列类型(slice/array)的元素 func cloneSequence(dst, src reflect.Value) { for i := 0; i < src.Len(); i++ { elem := src.Index(i) clonedElem := cloneElement(elem) dst.Index(i).Set(clonedElem) } } // cloneElement 克隆单个元素,处理 interface 包装的情况 // 对于复杂类型(struct, map, slice, array)和指针类型进行深度克隆 // 对于基本类型,直接返回原始值 func cloneElement(elem reflect.Value) reflect.Value { // 首先检查 elem 自身是否是 interface if elem.Kind() == reflect.Interface && !elem.IsNil() { // 获取 interface 包装的实际值 wrapped := elem.Elem() // 如果 interface 包装的是指针,需要深度克隆指针 if wrapped.Kind() == reflect.Ptr && !wrapped.IsNil() { // 克隆指针指向的值 pointedValue := wrapped.Elem() if needsDeepClone(pointedValue.Kind()) { // 复杂类型:递归克隆 clonedValue := reflect.New(pointedValue.Type()).Elem() CloneValue(clonedValue, pointedValue) clonedPtr := reflect.New(pointedValue.Type()) clonedPtr.Elem().Set(clonedValue) return clonedPtr } else { // 基本类型:创建新指针 clonedPtr := reflect.New(pointedValue.Type()) clonedPtr.Elem().Set(pointedValue) return clonedPtr } } // interface 包装的是复杂类型 if needsDeepClone(wrapped.Kind()) { clonedElem := reflect.New(wrapped.Type()).Elem() CloneValue(clonedElem, wrapped) return clonedElem } // interface 包装的是基本类型,直接返回 return elem } // 处理直接的指针类型 if elem.Kind() == reflect.Ptr && !elem.IsNil() { pointedValue := elem.Elem() if needsDeepClone(pointedValue.Kind()) { clonedValue := reflect.New(pointedValue.Type()).Elem() CloneValue(clonedValue, pointedValue) clonedPtr := reflect.New(pointedValue.Type()) clonedPtr.Elem().Set(clonedValue) return clonedPtr } else { // 基本类型的指针,创建新指针 clonedPtr := reflect.New(pointedValue.Type()) clonedPtr.Elem().Set(pointedValue) return clonedPtr } } // 处理复杂类型 if needsDeepClone(elem.Kind()) { clonedElem := reflect.New(elem.Type()).Elem() CloneValue(clonedElem, elem) return clonedElem } // 基本类型,直接返回 return elem } // needsDeepClone 判断某个类型是否需要深度克隆 func needsDeepClone(kind reflect.Kind) bool { return kind == reflect.Struct || kind == reflect.Map || kind == reflect.Slice || kind == reflect.Array } // expandPath 展开路径,支持点号分割 // 例如: expandPath("a.b", "c") -> []string{"a", "b", "c"} func expandPath(p ...string) []string { var result []string for _, segment := range p { // 按点号分割 parts := strings.Split(segment, ".") for _, part := range parts { if part != "" { // 忽略空字符串 result = append(result, part) } } } return result } // getValueByPath 通过路径获取值的辅助方法 // 支持两种路径格式: // 1. 多个参数: Get("Address", "City") // 2. 点号分割: Get("Address.City") 或混合使用 Get("Address.City", "ZipCode") func getValueByPath(v reflect.Value, p ...string) reflect.Value { for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { if v.IsNil() { return reflect.Value{} } v = v.Elem() } // 展开所有路径片段,支持点号分割 keys := expandPath(p...) for _, key := range keys { if !v.IsValid() { return reflect.Value{} } switch v.Kind() { case reflect.Struct: v = tryStructFieldValue(v, key) case reflect.Map: v = tryMapFieldValue(v, key) case reflect.Slice, reflect.Array: // 尝试将 key 转换为索引 idx, err := strconv.Atoi(key) if err == nil && idx >= 0 && idx < v.Len() { v = v.Index(idx) } else { return reflect.Value{} } default: return reflect.Value{} } // 解引用指针和接口 for v.IsValid() && (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) { if v.IsNil() { return reflect.Value{} } v = v.Elem() } } return v } // capitalizeFirst 将字符串首字母转换为大写 // 用于处理 struct 字段名,使其符合 Go 的公开字段命名规范 func capitalizeFirst(s string) string { if s == "" { return s } runes := []rune(s) runes[0] = unicode.ToUpper(runes[0]) return string(runes) } // lowercaseFirst 将字符串首字母转换为小写 func lowercaseFirst(s string) string { if s == "" { return s } runes := []rune(s) runes[0] = unicode.ToLower(runes[0]) return string(runes) } // tryStructFieldValue 尝试获取 struct 字段,支持小写字段名自动转大写 // 1. 首先尝试原始字段名 // 2. 如果失败且首字母是小写,尝试首字母大写的版本 func tryStructFieldValue(v reflect.Value, fieldName string) reflect.Value { // 首先尝试原始字段名 field := v.FieldByName(fieldName) if field.IsValid() { return field } // 如果字段名首字母是小写,尝试首字母大写 if len(fieldName) > 0 && unicode.IsLower(rune(fieldName[0])) { capitalizedName := capitalizeFirst(fieldName) field = v.FieldByName(capitalizedName) if field.IsValid() { return field } } return reflect.Value{} } // tryMapFieldValue 尝试从 map 中获取值,支持 string 键的小写字段名自动转大写 // 1. 首先使用原始 key 尝试 // 2. 如果 map 的键类型为 string 且 key 首字母是大写,再尝试首字母小写的版本 func tryMapFieldValue(m reflect.Value, key string) reflect.Value { actualKey := tryMapFieldKey(m, key) if !actualKey.IsValid() { return reflect.Value{} } return m.MapIndex(actualKey) } // tryMapFieldKey 尝试从 map 中获取实际存在的键 // 支持大小写不敏感查找 // 返回: 实际的键 func tryMapFieldKey(m reflect.Value, key string) reflect.Value { if !m.IsValid() || m.Kind() != reflect.Map { return reflect.Value{} } keyType := m.Type().Key() // 构造原始 key var mapKey reflect.Value if keyType.Kind() == reflect.String { mapKey = reflect.ValueOf(key) } else { // 非 string 键,尽量使用原始字符串构造可转换的 key raw := reflect.ValueOf(key) if raw.Type().AssignableTo(keyType) { mapKey = raw } else if raw.Type().ConvertibleTo(keyType) { mapKey = raw.Convert(keyType) } else { return reflect.Value{} } } // 尝试原始 key val := m.MapIndex(mapKey) if val.IsValid() { return mapKey } // 如果键类型是 string 且首字母大写,尝试首字母小写版本 if keyType.Kind() == reflect.String && len(key) > 0 && unicode.IsUpper(rune(key[0])) { lowercased := lowercaseFirst(key) mapKey = reflect.ValueOf(lowercased) val = m.MapIndex(mapKey) if val.IsValid() { return mapKey } } return reflect.Value{} } // normalizeAccessorSlice 规范化 Accessor 切片为 reflect.Value // 这个辅助函数用于处理 []R 和 []valuex.Accessor 的共同逻辑 func normalizeAccessorSlice[T valuex.Accessor](slice []T, typeName string) (reflect.Value, bool, error) { var elemType reflect.Type for _, it := range slice { // 检查是否为 nil (通过 any 转换检查) if any(it) == nil { continue } val := it.Raw() if val.IsValid() { elemType = val.Type() break } } // 如果所有元素都是 nil 或无效,返回 nil if elemType == nil { return reflect.ValueOf(nil), false, nil } // 创建底层切片 count := len(slice) rv := reflect.MakeSlice(reflect.SliceOf(elemType), count, count) for i, it := range slice { if any(it) == nil { continue } val := it.Raw() if !val.IsValid() { continue } if !val.Type().AssignableTo(elemType) { return rv, true, fmt.Errorf("rfx: []%s element type mismatch at index %d: got %s, want %s", typeName, i, val.Type(), elemType) } rv.Index(i).Set(val) } return rv, true, nil } // normalizeInputValue 规范化传入的任意值为 reflect.Value // 返回对应的 reflect.Value 以及是否应被视为指针(isPtr) func normalizeInputValue(v any) (reflect.Value, bool, error) { var rv reflect.Value var isPtr bool switch vv := v.(type) { case R: isPtr = true rv = vv.Raw() case valuex.Accessor: isPtr = true rv = vv.Raw() case []valuex.Accessor: return normalizeAccessorSlice(vv, "valuex.Accessor") case []R: return normalizeAccessorSlice(vv, "R") case reflect.Value: // 支持直接传入 reflect.Value,避免重复封装 rv = vv default: rv = reflect.ValueOf(v) } return rv, isPtr || rv.Kind() == reflect.Ptr, nil }