package structx import ( "reflect" "sync" ) // FieldMapper 字段映射器接口 type FieldMapper interface { GetFieldMap(t reflect.Type) map[string]FieldInfo } var ( // 全局缓存 避免重复计算 TODO: 考虑使用LRU缓存 typeInfoCache = make(map[reflect.Type]map[string]FieldInfo) cacheMutex = &sync.RWMutex{} ) // defaultFieldMapper 默认字段映射器 type defaultFieldMapper struct{} func (dm *defaultFieldMapper) GetFieldMap(t reflect.Type) map[string]FieldInfo { cacheMutex.RLock() if cached, exists := typeInfoCache[t]; exists { cacheMutex.RUnlock() return cached } cacheMutex.RUnlock() fieldMap := make(map[string]FieldInfo) dm.buildFieldMapRecursive(t, []int{}, fieldMap, "") cacheMutex.Lock() typeInfoCache[t] = fieldMap cacheMutex.Unlock() return fieldMap } // 递归构建字段映射表 func (dm *defaultFieldMapper) buildFieldMapRecursive(t reflect.Type, index []int, fieldMap map[string]FieldInfo, prefix string) { for i := 0; i < t.NumField(); i++ { field := t.Field(i) if !field.IsExported() { continue } currentIndex := append(index, i) jsonTag := getJSONTagName(field) fullKey := jsonTag if prefix != "" { fullKey = prefix + "." + jsonTag } fieldType := field.Type isPtr := fieldType.Kind() == reflect.Ptr actualType := fieldType if isPtr { // 解引用 actualType = fieldType.Elem() } if actualType.Kind() == reflect.Slice || actualType.Kind() == reflect.Array { fieldMap[fullKey] = FieldInfo{ Index: currentIndex, Name: field.Name, IsPtr: isPtr, FieldType: fieldType, IsSlice: actualType.Kind() == reflect.Slice, IsArray: actualType.Kind() == reflect.Array, } continue } if actualType.Kind() == reflect.Struct && !isBasicStructType(actualType) { dm.buildFieldMapRecursive(actualType, currentIndex, fieldMap, fullKey) } fieldMap[fullKey] = FieldInfo{ Index: currentIndex, Name: field.Name, IsPtr: isPtr, FieldType: fieldType, } } }