支持传入的跟结构就是数组 #4
							
								
								
									
										44
									
								
								builder.go
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								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 { | ||||
|  | ||||
| @ -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) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| @ -3,4 +3,6 @@ package dynamicstruct | ||||
| const ( | ||||
| 	// ArraySplit is the string used to split array elements | ||||
| 	ArraySplit = "[]" | ||||
| 	// ArrayRootFlag 传入路径直接以数组开头 | ||||
| 	ArrayRootFlag = "__RootArrayFlag" | ||||
| ) | ||||
|  | ||||
| @ -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() | ||||
| } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user