feat: 完善 normalizeInputValue 支持 valuex.Accessor 并优化代码

- 在 valuex.Accessor 接口中添加 Raw() 方法
- normalizeInputValue 支持 valuex.Accessor 和 []valuex.Accessor 类型
- 提取 normalizeAccessorSlice 泛型函数消除重复代码
- 使用 switch 语句替代 if-else 链提高可读性
- 添加相关测试用例确保功能正确性
This commit is contained in:
2025-12-16 16:14:46 +08:00
parent 7d17293df3
commit baad0cadfc
4 changed files with 118 additions and 38 deletions

92
util.go
View File

@@ -6,6 +6,8 @@ import (
"strconv"
"strings"
"unicode"
"git.fsdpf.net/go/reflux/valuex"
)
// DeepClone 深度克隆一个 reflect.Value
@@ -335,54 +337,68 @@ func tryMapFieldKey(m reflect.Value, key string) reflect.Value {
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
if vv, ok := v.(R); ok {
switch vv := v.(type) {
case R:
isPtr = true
rv = vv.Raw()
} else if vv, ok := v.([]R); ok {
// 支持直接传入 []R,自动转换为底层切片
var elemType reflect.Type
for _, it := range vv {
if it == nil {
continue
}
val := it.Raw()
if val.IsValid() {
elemType = val.Type()
break
}
}
// 如果所有元素都是 nil 或无效,退回到通用处理
if elemType == nil {
rv = reflect.ValueOf(nil)
} else {
isPtr = true
count := len(vv)
rv = reflect.MakeSlice(reflect.SliceOf(elemType), count, count)
for i, it := range vv {
if it == nil {
continue
}
val := it.Raw()
if !val.IsValid() {
continue
}
if !val.Type().AssignableTo(elemType) {
return rv, isPtr, fmt.Errorf("rfx: []R element type mismatch at index %d: got %s, want %s", i, val.Type(), elemType)
}
rv.Index(i).Set(val)
}
}
} else if vv, ok := v.(reflect.Value); ok {
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
} else {
default:
rv = reflect.ValueOf(v)
}