瀏覽代碼

add array struct and map supported

fancl 1 年之前
父節點
當前提交
9cfa81115f
共有 2 個文件被更改,包括 151 次插入38 次删除
  1. 113 32
      util/reflect/reflect.go
  2. 38 6
      util/reflection/reflection_test.go

+ 113 - 32
util/reflect/reflect.go

@@ -1,6 +1,7 @@
 package reflect
 
 import (
+	"errors"
 	"fmt"
 	"reflect"
 	"strconv"
@@ -11,6 +12,10 @@ var (
 	allowTags = []string{"json", "yaml", "xml", "name"}
 )
 
+var (
+	ErrValueAssociated = errors.New("value cannot be associated")
+)
+
 func findField(v reflect.Value, field string) reflect.Value {
 	var (
 		pos       int
@@ -64,7 +69,7 @@ func safeAssignment(variable reflect.Value, value interface{}) (err error) {
 				variable.SetInt(n)
 			}
 		default:
-			err = fmt.Errorf("unsupported kind %s", rv.Kind())
+			err = fmt.Errorf("integer value can not assign %s", rv.Kind())
 		}
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 		switch rv.Kind() {
@@ -79,7 +84,7 @@ func safeAssignment(variable reflect.Value, value interface{}) (err error) {
 				variable.SetUint(un)
 			}
 		default:
-			err = fmt.Errorf("unsupported kind %s", rv.Kind())
+			err = fmt.Errorf("unsigned integer value can not assign %s", rv.Kind())
 		}
 	case reflect.Float32, reflect.Float64:
 		switch rv.Kind() {
@@ -94,7 +99,7 @@ func safeAssignment(variable reflect.Value, value interface{}) (err error) {
 				variable.SetFloat(fn)
 			}
 		default:
-			err = fmt.Errorf("unsupported kind %s", rv.Kind())
+			err = fmt.Errorf("decimal value can not assign %s", rv.Kind())
 		}
 	case reflect.String:
 		switch rv.Kind() {
@@ -139,10 +144,30 @@ func Set(hacky interface{}, field string, value interface{}) (err error) {
 	}
 	switch fieldKind {
 	case reflect.Struct:
-		switch rv.Kind() {
-		case reflect.Map:
+		if rv.Kind() != reflect.Map {
+			return ErrValueAssociated
+		}
+		keys := rv.MapKeys()
+		subVal := reflect.New(refField.Type())
+		for _, key := range keys {
+			pv := rv.MapIndex(key)
+			if key.Kind() == reflect.String {
+				if err = Set(subVal.Interface(), key.String(), pv.Interface()); err != nil {
+					return err
+				}
+			}
+		}
+		refField.Set(subVal.Elem())
+	case reflect.Ptr:
+		elemType := refField.Type()
+		if elemType.Elem().Kind() != reflect.Struct {
+			return ErrValueAssociated
+		} else {
+			if rv.Kind() != reflect.Map {
+				return ErrValueAssociated
+			}
 			keys := rv.MapKeys()
-			subVal := reflect.New(refField.Type())
+			subVal := reflect.New(elemType.Elem())
 			for _, key := range keys {
 				pv := rv.MapIndex(key)
 				if key.Kind() == reflect.String {
@@ -151,46 +176,102 @@ func Set(hacky interface{}, field string, value interface{}) (err error) {
 					}
 				}
 			}
-			refField.Set(subVal.Elem())
-		default:
-			err = fmt.Errorf("struct unsupported assign kind %s", rv.Kind())
+			refField.Set(subVal)
 		}
-	case reflect.Ptr:
-		elemType := refField.Type()
-		if elemType.Elem().Kind() == reflect.Struct {
-			switch rv.Kind() {
-			case reflect.Map:
-				keys := rv.MapKeys()
-				subVal := reflect.New(elemType.Elem())
-				for _, key := range keys {
-					pv := rv.MapIndex(key)
-					if key.Kind() == reflect.String {
-						if err = Set(subVal.Interface(), key.String(), pv.Interface()); err != nil {
+	case reflect.Map:
+		if rv.Kind() != reflect.Map {
+			return ErrValueAssociated
+		}
+		targetValue := reflect.MakeMap(refField.Type())
+		keys := rv.MapKeys()
+		for _, key := range keys {
+			pv := rv.MapIndex(key)
+			kVal := reflect.New(refField.Type().Key())
+			eVal := reflect.New(refField.Type().Elem())
+			if err = safeAssignment(kVal.Elem(), key.Interface()); err != nil {
+				return ErrValueAssociated
+			}
+			if refField.Type().Elem().Kind() == reflect.Struct {
+				if pv.Elem().Kind() != reflect.Map {
+					return ErrValueAssociated
+				}
+				subKeys := pv.Elem().MapKeys()
+				for _, subKey := range subKeys {
+					subVal := pv.Elem().MapIndex(subKey)
+					if subKey.Kind() == reflect.String {
+						if err = Set(eVal.Interface(), subKey.String(), subVal.Interface()); err != nil {
 							return err
 						}
 					}
 				}
-				refField.Set(subVal)
-			default:
-				err = fmt.Errorf("struct unsupported assign kind %s", rv.Kind())
+				targetValue.SetMapIndex(kVal.Elem(), eVal.Elem())
+			} else {
+				if err = safeAssignment(eVal.Elem(), pv.Interface()); err != nil {
+					return ErrValueAssociated
+				}
+				targetValue.SetMapIndex(kVal.Elem(), eVal.Elem())
 			}
-		} else {
-			err = fmt.Errorf("ptr can't set kind %s", elemType.Elem().Kind())
 		}
+		refField.Set(targetValue)
 	case reflect.Array, reflect.Slice:
+		n = 0
 		innerType := refField.Type().Elem()
 		if rv.Kind() == reflect.Array || rv.Kind() == reflect.Slice {
-			sliceVar := reflect.MakeSlice(refField.Type(), rv.Len(), rv.Len())
-			n = 0
-			for i := 0; i < rv.Len(); i++ {
-				srcVal := rv.Index(i)
-				dstVal := reflect.New(innerType).Elem()
-				if err = safeAssignment(dstVal, srcVal); err == nil {
+			if innerType.Kind() == reflect.Struct {
+				sliceVar := reflect.MakeSlice(refField.Type(), rv.Len(), rv.Len())
+				for i := 0; i < rv.Len(); i++ {
+					srcVal := rv.Index(i)
+					if srcVal.Kind() != reflect.Map {
+						return ErrValueAssociated
+					}
+					dstVal := reflect.New(innerType)
+					keys := srcVal.MapKeys()
+					for _, key := range keys {
+						kv := srcVal.MapIndex(key)
+						if key.Kind() == reflect.String {
+							if err = Set(dstVal.Interface(), key.String(), kv.Interface()); err != nil {
+								return
+							}
+						}
+					}
+					sliceVar.Index(n).Set(dstVal.Elem())
+					n++
+				}
+				refField.Set(sliceVar.Slice(0, n))
+			} else if innerType.Kind() == reflect.Ptr {
+				sliceVar := reflect.MakeSlice(refField.Type(), rv.Len(), rv.Len())
+				for i := 0; i < rv.Len(); i++ {
+					srcVal := rv.Index(i)
+					if srcVal.Kind() != reflect.Map {
+						return ErrValueAssociated
+					}
+					dstVal := reflect.New(innerType.Elem())
+					keys := srcVal.MapKeys()
+					for _, key := range keys {
+						kv := srcVal.MapIndex(key)
+						if key.Kind() == reflect.String {
+							if err = Set(dstVal.Interface(), key.String(), kv.Interface()); err != nil {
+								return
+							}
+						}
+					}
+					sliceVar.Index(n).Set(dstVal)
+					n++
+				}
+				refField.Set(sliceVar.Slice(0, n))
+			} else {
+				sliceVar := reflect.MakeSlice(refField.Type(), rv.Len(), rv.Len())
+				for i := 0; i < rv.Len(); i++ {
+					srcVal := rv.Index(i)
+					dstVal := reflect.New(innerType).Elem()
+					if err = safeAssignment(dstVal, srcVal.Interface()); err != nil {
+						return
+					}
 					sliceVar.Index(n).Set(dstVal)
 					n++
 				}
+				refField.Set(sliceVar.Slice(0, n))
 			}
-			refField.Set(sliceVar.Slice(0, n))
 		}
 	default:
 		err = safeAssignment(refField, value)

+ 38 - 6
util/reflection/reflection_test.go

@@ -6,17 +6,50 @@ import (
 )
 
 type Fakeb struct {
-	In int `json:"in"`
+	In int               `json:"in"`
+	BS map[string]string `json:"bs"`
 }
+
+type Ab struct {
+	Name string `json:"name"`
+}
+
 type fake struct {
-	Name  string `json:"name"`
-	Age   int    `json:"age"`
-	Usage *Fakeb `json:"usage"`
+	Name  string         `json:"name"`
+	Age   int            `json:"age"`
+	Usage []Fakeb        `json:"usage"`
+	XX    Fakeb          `json:"xx"`
+	AX    *Fakeb         `json:"ax"`
+	SS    []string       `json:"ss"`
+	DS    []int          `json:"ds"`
+	Ms    map[string]int `json:"ms"`
+	AB    map[string]Ab  `json:"ab"`
 }
 
 func TestSetter(t *testing.T) {
 	dst := &fake{}
-	ms := map[string]any{"name": "aa", "age": "5", "usage": map[string]any{"in": 15}}
+	ms := map[string]any{
+		"name": "aa",
+		"age":  "5",
+		"usage": []map[string]any{
+			{
+				"in": 15,
+				"bs": map[string]any{
+					"aa": "vv",
+				},
+			},
+		},
+		"xx": map[string]any{"in": 45},
+		"ax": map[string]any{"in": 55},
+		"ss": []string{"11", "ss"},
+		"ds": []int{55, 55, 34},
+		"ms": map[string]any{"aa": "23"},
+		"ab": map[string]any{
+			"xx": map[string]any{
+				"name": "xxx",
+			},
+		},
+	}
 	err := Setter(dst, ms)
 	if err != nil {
 		t.Error(err)
@@ -25,7 +58,6 @@ func TestSetter(t *testing.T) {
 	if dst.Age != 5 {
 		t.Errorf("setter failed")
 	} else {
-		fmt.Println(dst.Usage.In)
 		fmt.Printf("%+v", dst)
 	}
 }