89 lines
2.0 KiB
Go
89 lines
2.0 KiB
Go
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,
|
|
}
|
|
}
|
|
}
|