feat: 支持嵌套 R 和 valuex.Accessor 对象的路径访问
- 添加 unwrapAccessor 统一处理 Accessor 解引用 - 添加 deref/derefWithAccessor/derefValue 封装重复的解引用逻辑 - getValueByPath 支持穿透 R/Accessor 对象访问嵌套路径 - setNestedValue 支持在 R/Accessor 对象中设置嵌套值 - CloneValue 和 cloneElement 正确克隆 Accessor 底层值 - 支持在 map/struct/slice 中嵌套 R 对象并通过路径访问 - 添加完整测试覆盖 map/struct/slice/深度嵌套等场景 - 减少 38 行重复代码,提高代码可维护性
This commit is contained in:
84
util.go
84
util.go
@@ -13,12 +13,7 @@ import (
|
||||
// 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()
|
||||
}
|
||||
v = deref(v)
|
||||
|
||||
if !v.IsValid() {
|
||||
return reflect.Value{}
|
||||
@@ -48,6 +43,19 @@ func CloneValue(dst, src reflect.Value) {
|
||||
if src.IsNil() {
|
||||
return
|
||||
}
|
||||
|
||||
// 解引用 Accessor,克隆其底层值
|
||||
unwrapped := unwrapAccessor(src)
|
||||
if unwrapped != src {
|
||||
// 是 Accessor,克隆底层值
|
||||
cloned := DeepClone(unwrapped)
|
||||
if cloned.IsValid() {
|
||||
dst.Set(cloned)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 不是 Accessor,正常克隆
|
||||
cloned := DeepClone(src.Elem())
|
||||
if cloned.IsValid() {
|
||||
dst.Set(cloned)
|
||||
@@ -104,6 +112,13 @@ func cloneSequence(dst, src reflect.Value) {
|
||||
func cloneElement(elem reflect.Value) reflect.Value {
|
||||
// 首先检查 elem 自身是否是 interface
|
||||
if elem.Kind() == reflect.Interface && !elem.IsNil() {
|
||||
// 检查并解引用 Accessor
|
||||
unwrapped := unwrapAccessor(elem)
|
||||
if unwrapped != elem {
|
||||
// 是 Accessor,克隆底层值
|
||||
return DeepClone(unwrapped)
|
||||
}
|
||||
|
||||
// 获取 interface 包装的实际值
|
||||
wrapped := elem.Elem()
|
||||
|
||||
@@ -173,6 +188,49 @@ func needsDeepClone(kind reflect.Kind) bool {
|
||||
kind == reflect.Array
|
||||
}
|
||||
|
||||
// unwrapAccessor 解引用 valuex.Accessor (包括 R),返回其底层值
|
||||
// 如果 v 不是 interface 或不包含 Accessor,返回原值
|
||||
func unwrapAccessor(v reflect.Value) reflect.Value {
|
||||
if v.Kind() == reflect.Interface && !v.IsNil() {
|
||||
if accessor, ok := v.Interface().(valuex.Accessor); ok {
|
||||
rawVal := accessor.Raw()
|
||||
if rawVal.IsValid() {
|
||||
return rawVal
|
||||
}
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// derefValue 递归解引用指针和接口,返回实际值
|
||||
// nilValue: 遇到 nil 时返回的值
|
||||
// supportAccessor: 是否支持解引用 Accessor
|
||||
func derefValue(v reflect.Value, nilValue reflect.Value, supportAccessor bool) reflect.Value {
|
||||
for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
|
||||
if v.IsNil() {
|
||||
return nilValue
|
||||
}
|
||||
if supportAccessor {
|
||||
v = unwrapAccessor(v)
|
||||
if v.Kind() != reflect.Ptr && v.Kind() != reflect.Interface {
|
||||
break
|
||||
}
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// deref 递归解引用指针和接口,返回实际值(nil 时返回无效值)
|
||||
func deref(v reflect.Value) reflect.Value {
|
||||
return derefValue(v, reflect.Value{}, false)
|
||||
}
|
||||
|
||||
// derefWithAccessor 递归解引用指针和接口(支持 Accessor),返回实际值(nil 时返回无效值)
|
||||
func derefWithAccessor(v reflect.Value) reflect.Value {
|
||||
return derefValue(v, reflect.Value{}, true)
|
||||
}
|
||||
|
||||
// expandPath 展开路径,支持点号分割
|
||||
// 例如: expandPath("a.b", "c") -> []string{"a", "b", "c"}
|
||||
func expandPath(p ...string) []string {
|
||||
@@ -194,12 +252,7 @@ func expandPath(p ...string) []string {
|
||||
// 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()
|
||||
}
|
||||
v = derefWithAccessor(v)
|
||||
|
||||
// 展开所有路径片段,支持点号分割
|
||||
keys := expandPath(p...)
|
||||
@@ -227,12 +280,7 @@ func getValueByPath(v reflect.Value, p ...string) reflect.Value {
|
||||
}
|
||||
|
||||
// 解引用指针和接口
|
||||
for v.IsValid() && (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) {
|
||||
if v.IsNil() {
|
||||
return reflect.Value{}
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
v = derefWithAccessor(v)
|
||||
}
|
||||
|
||||
return v
|
||||
|
||||
Reference in New Issue
Block a user