diff --git a/builder.go b/builder.go index 8a04d5f..2dea003 100644 --- a/builder.go +++ b/builder.go @@ -178,6 +178,9 @@ func (b *builderImpl) Build() IDynamicStruct { for deep := b.maxFieldDeep - 1; deep > 0; deep-- { // 嵌套数据结构 for parentIndex, builderCfg := range b.nestedStructTable { + if parentIndex == ArrayRootFlag { + continue + } parentNameArr := strings.Split(parentIndex, ".") if len(parentNameArr) != deep { // 从深度最深处向上处理 @@ -201,24 +204,40 @@ func (b *builderImpl) Build() IDynamicStruct { } if arrDeep > 0 { // 数组嵌套数组配置 - val := reflect.ValueOf(builderCfg.Builder.Build().New()).Elem().Interface() + val := reflect.ValueOf(builderCfg.Builder.Build().New()).Interface() for i := 0; i < arrDeep; i++ { - val = reflect.New(reflect.SliceOf(reflect.TypeOf(val))).Interface() + val = reflect.New(reflect.SliceOf(reflect.TypeOf(val).Elem())).Interface() + // 删除数组记录 + arrPath := strings.Join(parentNameArr[:len(parentNameArr)-i], ".") + delete(b.nestedStructTable, arrPath) } - // 解除指针引用 - // val = reflect.ValueOf(val).Elem().Interface() - newParamIndex := strings.Join(newParentNameArr, ".") + newParentIndex := strings.Join(newParentNameArr, ".") isTopIndex := len(newParentNameArr) == 1 if isTopIndex { // 顶层结构, 数组类型不存在还有其他属性情况, 直接追加字段, 并移除嵌套表里的定义 - b.AddField(b.nestedStructTable[newParamIndex].Field, "", val, b.nestedStructTable[newParamIndex].Tag, false) + b.AddField(b.nestedStructTable[newParentIndex].Field, "", val, b.nestedStructTable[newParentIndex].Tag, false) // b.nestedStructTable[newParamIndex].Builder.AddField(b.nestedStructTable[newParamIndex].Field, "", val, b.nestedStructTable[newParamIndex].Tag, false) } else { // 非顶层结构, 再上探一级 - b.nestedStructTable[strings.Join(newParentNameArr[:len(newParentNameArr)-1], ".")].Builder.AddField(b.nestedStructTable[newParamIndex].Field, "", val, b.nestedStructTable[newParamIndex].Tag, false) + newParentName := "" + fieldName := "" + if len(newParentNameArr) == 0 { + // 说明传入的直接就是数组 + newParentName = ArrayRootFlag + fieldName = ArrayRootFlag + b.nestedStructTable[newParentName] = nestedStruct{ + Field: fieldName, + Builder: NewStruct(b.structTagTable), + Tag: "", + } + b.nestedStructTable[newParentName].Builder.AddField(b.nestedStructTable[newParentName].Field, "", reflect.ValueOf(val).Elem().Interface(), b.nestedStructTable[newParentName].Tag, false) + } else { + newParentName = strings.Join(newParentNameArr[:len(newParentNameArr)-1], ".") + b.nestedStructTable[newParentName].Builder.AddField(b.nestedStructTable[newParentIndex].Field, "", reflect.ValueOf(val).Elem().Interface(), b.nestedStructTable[newParentIndex].Tag, false) + } } // 嵌套结构中删除数组字段 - delete(b.nestedStructTable, newParamIndex) + delete(b.nestedStructTable, newParentIndex) } else { // 非数组 // (非顶层) 父级结构存在, 将其追加到父级结构中即可, 向前看一步即为父级结构 @@ -227,6 +246,15 @@ func (b *builderImpl) Build() IDynamicStruct { } } } + + if nestedCfg, exist := b.nestedStructTable[ArrayRootFlag]; exist { + // 说明是传入的根路径就是数组 + return &dynamicStructImpl{ + structFields: nil, + definition: reflect.TypeOf(nestedCfg.Builder.GetField(ArrayRootFlag).GetType()), + } + } + // 一级字段属性 var structFields []reflect.StructField for _, field := range b.fields { diff --git a/builder_test.go b/builder_test.go index 08b1cc4..84e94df 100644 --- a/builder_test.go +++ b/builder_test.go @@ -223,3 +223,45 @@ func TestExtendStruct(t *testing.T) { So(instance.GetField("Age").GetTag(), ShouldEqual, `json:"company_age"`) }) } + +func TestArrayRoot(t *testing.T) { + Convey("嵌套结构体带多级数组", t, func() { + data := []byte(` +[[[{ + "age": 123, + "name": "example", + "double": 123.45, + "bool": true, + "slice": [1, 2, 3] + }]]] + `) + instance := NewStruct(map[string]string{ + "test_tag_map": `json:"tag_map"`, + }). + AddField("[].[].[].age", "", 0, `json:"age"`, false). + AddField("[].[].[].name", "", "", `json:"name"`, false). + Build() + val := instance.New() + err := json.Unmarshal(data, &val) + So(err, ShouldBeNil) + reflectType := reflect.TypeOf(val) + // 需要是数组类型 + So(reflectType.Kind(), ShouldEqual, reflect.Ptr) + So(reflectType.Elem().Kind(), ShouldEqual, reflect.Slice) + // 验证数据 + // 数据序列化成功 + targetByte, targetErr := json.Marshal(val) + So(targetErr, ShouldBeNil) + // 数据转map成功 + var res [][][]any + targetUnmarshalErr := json.Unmarshal(targetByte, &res) + So(targetUnmarshalErr, ShouldBeNil) + So(len(res), ShouldEqual, 1) + userMap, ok := res[0][0][0].(map[string]any) + So(ok, ShouldBeTrue) + So(len(userMap), ShouldEqual, 2) + So(userMap["age"], ShouldEqual, float64(123)) + So(userMap["name"], ShouldEqual, "example") + So(userMap["double"], ShouldBeNil) + }) +} diff --git a/define.go b/define.go index a9e497c..a12388a 100644 --- a/define.go +++ b/define.go @@ -3,4 +3,6 @@ package dynamicstruct const ( // ArraySplit is the string used to split array elements ArraySplit = "[]" + // ArrayRootFlag 传入路径直接以数组开头 + ArrayRootFlag = "__RootArrayFlag" ) diff --git a/dynamic_struct.go b/dynamic_struct.go index fcf16e4..0aff47e 100644 --- a/dynamic_struct.go +++ b/dynamic_struct.go @@ -7,7 +7,9 @@ // Date : 2025-03-23 14:14 package dynamicstruct -import "reflect" +import ( + "reflect" +) type dynamicStructImpl struct { structFields []reflect.StructField @@ -16,7 +18,6 @@ type dynamicStructImpl struct { // New 创建动态结构体实例 func (ds *dynamicStructImpl) New() any { - // 不要指针,全部解引用 return reflect.New(ds.definition).Interface() }