feat: 支持切片追加及 -1 头部插入

This commit is contained in:
2025-12-04 11:28:18 +08:00
parent cbe079ddcd
commit b373dde7f7
4 changed files with 139 additions and 8 deletions

67
rfx.go
View File

@@ -115,6 +115,42 @@ func (r *rfx) Set(key string, v any) R {
return r
}
// Append 追加指定路径的值
// 参数 items 为要追加的值
// 返回当前 R 实例以支持链式调用
func (r *rfx) Append(items ...any) R {
// 没有要追加的元素,直接返回
if len(items) == 0 {
return r
}
target := r.getParentValue()
for target.Kind() == reflect.Ptr || target.Kind() == reflect.Interface {
if target.IsNil() {
panic("rfx: cannot append to nil value")
}
target = target.Elem()
}
if !target.IsValid() || target.Kind() != reflect.Slice {
panic("rfx: Append only supports slice type")
}
// 一次性构造所有要追加的元素,然后调用一次 reflect.Append
elemType := target.Type().Elem()
newValues := make([]reflect.Value, len(items))
for i, item := range items {
newElem := reflect.New(elemType).Elem()
if !r.setValue(newElem, item) {
panic("rfx: failed to append item to slice")
}
newValues[i] = newElem
}
target.Set(reflect.Append(target, newValues...))
return r
}
// setNestedValue 递归设置嵌套值,特殊处理 map 中的 struct
func (r *rfx) setNestedValue(current reflect.Value, keys []string, v any) bool {
// 解引用指针和接口
@@ -232,7 +268,36 @@ func (r *rfx) setFieldValue(target reflect.Value, key string, v any) bool {
}
target.SetMapIndex(reflect.ValueOf(key), val)
return true
case reflect.Slice, reflect.Array:
case reflect.Slice:
idx, err := strconv.Atoi(key)
if err != nil {
return false
}
// 对于切片,支持使用索引 -1 追加新元素(插入到切片前面)
if idx == -1 {
elemType := target.Type().Elem()
newElem := reflect.New(elemType).Elem()
if !r.setValue(newElem, v) {
return false
}
// 将新元素放在前面,原有元素顺序后移
newSlice := reflect.MakeSlice(target.Type(), 0, target.Len()+1)
newSlice = reflect.Append(newSlice, newElem)
newSlice = reflect.AppendSlice(newSlice, target)
target.Set(newSlice)
return true
}
if idx < 0 || idx >= target.Len() {
return false
}
elem := target.Index(idx)
if !elem.CanSet() {
return false
}
return r.setValue(elem, v)
case reflect.Array:
idx, err := strconv.Atoi(key)
if err != nil || idx < 0 || idx >= target.Len() {
return false