/** * 创建结构体递归遍历子字段操作 * * @param structV 递归操作字段 * @param joinFieldName 字段连接名 * @param arraySizeMap 解析后的集合数量设值map */ func parampackNewStructFindFiled(structV reflect.Value, joinFieldName string, arraySizeMap map[string]int) { structV = reflect.Indirect(structV) if reflect.Struct != structV.Kind() { return } // 遍历结构字段寻找需要初始化的slice filedCount := structV.NumField() for i := 0; i < filedCount; i++ { childField := structV.Field(i) childFieldType := childField.Type() childFieldName := structV.Type().Field(i).Name if !childField.CanSet() { continue } if 0 != len(joinFieldName) && '.' != joinFieldName[len(joinFieldName)-1] { joinFieldName += "." } if reflect.Ptr == childFieldType.Kind() && childField.IsNil() { // 初始化子结构指针的操作 childField.Set(reflect.New(childField.Type().Elem())) } switch reflect.Indirect(childField).Kind() { case reflect.Struct: if !parampackFilterParamPackStructType(childField.Type()) { parampackNewStructFindFiled(childField, joinFieldName+childFieldName, arraySizeMap) } case reflect.Slice: tempJoinName := joinFieldName + childFieldName if sliceSize, ok := arraySizeMap[strings.ToLower(tempJoinName)]; ok { valueElem := reflect.Indirect(childField) valueElem.Set(reflect.MakeSlice(valueElem.Type(), sliceSize, sliceSize)) // 继续执行集合子元素的遍历 if !parampackFilterParamPackStructType(valueElem.Type()) { for j := 0; j < sliceSize; j++ { childIndex := valueElem.Index(j) if reflect.Ptr == childIndex.Kind() && childIndex.IsNil() { // 初始化子元素指针的操作 childIndex.Set(reflect.New(childIndex.Type().Elem())) } // 当前由于是数组类型,所以传递连接名的时候加上"[index]"下标往下进行操作 tempJoinName = joinFieldName + childFieldName + "[" + strconv.Itoa(j) + "]" parampackNewStructFindFiled(childIndex, tempJoinName, arraySizeMap) } } } } } }
/** * 根据field的字段名称设置struct字段属性值 * 字段名称可为"type.tag.TagName", 以"."作为子字段的名称分割 * * @param sutValue 被设值的结构反射类型 * @param fieldName 字段名(type.tag.TagName) or (tagnName) * @param value 设值值 */ func parampackSetStructFieldValue(sutValue reflect.Value, fieldName string, value interface{}) { fieldName = strings.TrimSpace(fieldName) sutValueElem := reflect.Indirect(sutValue) if len(fieldName) == 0 { return } // 由于考虑到key的值可能为(type.tag.TagName),嵌套的赋值,所以需要进行"."的分割,每次获取slice的第一项 fieldsName := strings.Split(fieldName, ".") childFieldName := strings.Title(fieldsName[0]) if sutValueElem.Kind() == reflect.Slice { // 集合字段的设值操作 strIndex := _arrayTagRex.FindString(childFieldName) if 0 >= len(strIndex) { // 判断如果是数组类型,但是设值的字段名称不是数组的标识则跳过(数组标识Users[0]) // 由于有可能是需要直接设置数组参数,但是字段名称中(childFieldName = "Files")中未包含"[\d]"的标识 // 所以尝试直接设值 parampackSetParamValue(sutValueElem, fieldName, value) return } intIndex, e := strconv.Atoi(strIndex[1 : len(strIndex)-1]) if nil == e && intIndex < sutValueElem.Len() { fieldValue := sutValueElem.Index(intIndex) parampackSetFieldValue(fieldValue, fieldName, fieldsName, value) } } else { // 判断是否为数组标识,如果是的话就删除,例如:Users[0] 删除[0] = Users // 这样便于FieldByName查找到相应的字段信息 reIndex := _arrayTagRex.FindStringIndex(childFieldName) if 0 < len(reIndex) { childFieldName = childFieldName[:reIndex[0]] } // 查找字段 fieldValue := sutValueElem.FieldByName(childFieldName) parampackSetFieldValue(fieldValue, fieldName, fieldsName, value) } }