diff --git a/README.md b/README.md index 406a85e..b4cf6e8 100644 --- a/README.md +++ b/README.md @@ -21,42 +21,6 @@ go get github.com/sunfmin/reflectutils - -* [Variables](#variables) -* [Get](#get) -* [Must Get](#must-get) -* [Set](#set) - - -## Variables -``` go -var NoSuchFieldError = errors.New("no such field.") -``` - - -## Get -``` go -func Get(i interface{}, name string) (value interface{}, err error) -``` -Get value of a struct by path using reflect. - - - -## Must Get -``` go -func MustGet(i interface{}, name string) (value interface{}) -``` -MustGet get value of a struct by path using reflect, return nil if anything in the path is nil - - - -## Set -``` go -func Set(i interface{}, name string, value interface{}) (err error) -``` -Set value of a struct by path using reflect. - - By given these structs ```go type Person struct { @@ -355,6 +319,39 @@ If you set a property that don't exists, it gives you an error. // no such field. ``` +Get Type of a deep nested object +```go + type Variant struct { + Name string + } + type Product struct { + Variants []*Variant + ByCode map[string]*Variant + } + type Obj struct { + MainProduct *Product + } + + var o *Obj + + fmt.Println(GetType(o, "MainProduct.Variants[0].Name")) + fmt.Println(GetType(o, "MainProduct.Variants[0]")) + fmt.Println(GetType(o, "MainProduct.Variants")) + fmt.Println(GetType(o, "MainProduct")) + fmt.Println(GetType(o, "MainProduct.ByCode.abc")) + fmt.Println(GetType(o, "MainProduct.ByCode")) + fmt.Println(GetType(o, "x123.ByCode")) + fmt.Println(GetType(o, "MainProduct.ByCode.abc.NotExist")) + //Output: + //string + //*reflectutils_test.Variant + //[]*reflectutils_test.Variant + //*reflectutils_test.Product + //*reflectutils_test.Variant + //map[string]*reflectutils_test.Variant + // + // +``` diff --git a/example_test.go b/example_test.go index 837ddc1..138f82f 100644 --- a/example_test.go +++ b/example_test.go @@ -306,6 +306,41 @@ func ExampleSet_7notexists() { // no such field. } + +// Get Type of a deep nested object +func ExampleSet_8gettype() { + type Variant struct { + Name string + } + type Product struct { + Variants []*Variant + ByCode map[string]*Variant + } + type Obj struct { + MainProduct *Product + } + + var o *Obj + + fmt.Println(GetType(o, "MainProduct.Variants[0].Name")) + fmt.Println(GetType(o, "MainProduct.Variants[0]")) + fmt.Println(GetType(o, "MainProduct.Variants")) + fmt.Println(GetType(o, "MainProduct")) + fmt.Println(GetType(o, "MainProduct.ByCode.abc")) + fmt.Println(GetType(o, "MainProduct.ByCode")) + fmt.Println(GetType(o, "x123.ByCode")) + fmt.Println(GetType(o, "MainProduct.ByCode.abc.NotExist")) + //Output: + //string + //*reflectutils_test.Variant + //[]*reflectutils_test.Variant + //*reflectutils_test.Product + //*reflectutils_test.Variant + //map[string]*reflectutils_test.Variant + // + // +} + func printJsonV(v interface{}) { j, _ := json.MarshalIndent(v, "", "\t") fmt.Printf("\n\n%s\n", j) diff --git a/get_type.go b/get_type.go new file mode 100644 index 0000000..aee5ed5 --- /dev/null +++ b/get_type.go @@ -0,0 +1,52 @@ +package reflectutils + +import ( + "reflect" + "strings" +) + +// Get value of a struct by path using reflect. +func GetType(i interface{}, name string) (t reflect.Type) { + var err error + + t = reflect.TypeOf(i) + + if name == "" { + return + } + + var token *dotToken + token, err = nextDot(name) + if err != nil { + return nil + } + + if t.Kind() == reflect.Map || t.Kind() == reflect.Slice { + t = GetType(reflect.Zero(t.Elem()).Interface(), token.Left) + return + } + + if t.Kind() != reflect.Struct { + for t.Elem().Kind() == reflect.Ptr { + t = t.Elem() + } + + t = t.Elem() + } + + if t.Kind() == reflect.Struct { + + sf, ok := t.FieldByNameFunc(func(name string) bool { + return strings.EqualFold(name, token.Field) + }) + + if !ok { + return nil + } + + t = GetType(reflect.Zero(sf.Type).Interface(), token.Left) + return + } + + return +}