diff --git a/27-reflection/reflection/main.go b/27-reflection/reflection/main.go index 550f0eb..97cd9ee 100644 --- a/27-reflection/reflection/main.go +++ b/27-reflection/reflection/main.go @@ -22,4 +22,7 @@ func main() { main22() main23() main24() + main25() + main26() + main27() } diff --git a/27-reflection/reflection/re2.go b/27-reflection/reflection/re2.go index 0b220c3..243339e 100644 --- a/27-reflection/reflection/re2.go +++ b/27-reflection/reflection/re2.go @@ -314,3 +314,141 @@ func main24() { Printfln("Key: %v, Value: %v", key, val) } } + +func inspectStructs(structs ...interface{}) { + for _, s := range structs { + structType := reflect.TypeOf(s) + if structType.Kind() == reflect.Struct { + inspectStructType("main", []int{}, structType, structType) + } + } +} + +func inspectStructType(tag string, baseIndex []int, structType reflect.Type, baseType reflect.Type) { + Printfln("--- %v Struct Type: %v", tag, structType) + for i := 0; i < structType.NumField(); i++ { + fieldIndex := append(baseIndex, i) + field := structType.Field(i) + Printfln("%v - Field Base Index : %v , Field Index %v: Name:%v, Type:%v, Tag:%v , PkgPath:%v", + tag, fieldIndex, field.Index, field.Name, field.Type, field.Tag, field.PkgPath) + + if field.Type.Kind() == reflect.Struct { + inspectStructType("field", fieldIndex, field.Type, baseType) + + fieldWithFieldIndex := baseType.FieldByIndex(fieldIndex) + inspectStructType("fieldWithFieldIndex", fieldIndex, fieldWithFieldIndex.Type, baseType) + } + + } + Printfln("--- End %v Struct Type: %v", tag, structType) +} + +func describeField(s interface{}, fieldName string) { + Printfln("\ndescribeField:") + structType := reflect.TypeOf(s) + field, found := structType.FieldByName(fieldName) + if found { + Printfln("Top-Level Type: %v, Name: %v, Type: %v, Index: %v, Tag:%v , PkgPath:%v", + structType, field.Name, field.Type, field.Index, field.Tag, field.PkgPath) + index := field.Index + + for len(index) > 1 { + index = index[0 : len(index)-1] + parentField := structType.FieldByIndex(index) + Printfln("Parent Name: %v, Type: %v, Index: %v, Tag:%v , PkgPath:%v", + parentField.Name, parentField.Type, parentField.Index, parentField.Tag, parentField.PkgPath) + } + } else { + Printfln("Field %v not found", fieldName) + } +} + +func main25() { + Printfln("\nmain25:") + + inspectStructs(Purchase{}) + + describeField(Purchase{}, "Price") +} + +func inspectTags(s interface{}, tagName string) { + structType := reflect.TypeOf(s) + for i := 0; i < structType.NumField(); i++ { + field := structType.Field(i) + tag := field.Tag + + valGet := tag.Get(tagName) + valLookup, ok := tag.Lookup(tagName) + + Printfln("Field Name: %v, Type: %v, Tag: %v, TagName: %v, Get: %v, Lookup: %v, LookupOk: %v", + field.Name, field.Type, tag, tagName, valGet, valLookup, ok) + } +} + +func main26() { + Printfln("\nmain26:") + inspectTags(Person{}, "alias") + + stringType := reflect.TypeOf("") + structType := reflect.StructOf([]reflect.StructField{ + {Name: "Name", Type: stringType, Tag: `alias:"id"`}, + {Name: "City", Type: stringType, Tag: `alias:""`}, + {Name: "Country", Type: stringType}, + }) + inspectTags(reflect.New(structType), "alias") + inspectTags(reflect.New(structType).Elem().Interface(), "alias") +} + +func getFieldValues(s interface{}) { + structValue := reflect.ValueOf(s) + if structValue.Kind() != reflect.Struct { + Printfln("Not a struct") + return + } + for i := 0; i < structValue.NumField(); i++ { + fieldType := structValue.Type().Field(i) + fieldVal := structValue.Field(i) + Printfln("Name: %v, Type: %v, Value: %v", fieldType.Name, fieldType.Type, fieldVal) + } +} + +func setFieldValues(s interface{}, newVals map[string]interface{}) { + structValue := reflect.ValueOf(s) + if structValue.Kind() != reflect.Ptr || structValue.Elem().Kind() != reflect.Struct { + Printfln("Not a pointer to a struct") + return + } + structValue = structValue.Elem() + for name, newValue := range newVals { + fieldVal := structValue.FieldByName(name) + if fieldVal.CanSet() { + fieldVal.Set(reflect.ValueOf(newValue)) + } else if fieldVal.CanAddr() { + ptr := fieldVal.Addr() + if ptr.CanSet() { + ptr.Set(reflect.ValueOf(newValue)) + } else { + Printfln("Can't set field via pointer: %v", name) + } + } else { + Printfln("Can't set field: %v", name) + } + } +} + +func main27() { + Printfln("\nmain27:") + + product := Product{Name: "Kayak", Category: "Watersports", Price: 279} + customer := Customer{Name: "Acme", City: "Chicago"} + Purchase := Purchase{Customer: customer, Product: product, Total: 279, taxRate: 10} + getFieldValues(Purchase) + + Printfln("sets:") + setFieldValues(&Purchase, map[string]interface{}{ + "City": "London", + "Category": "Boats", + "Total": 100.50, + }) + getFieldValues(Purchase) +} diff --git a/27-reflection/reflection/types.go b/27-reflection/reflection/types.go index 3757f2b..1b9eb2e 100644 --- a/27-reflection/reflection/types.go +++ b/27-reflection/reflection/types.go @@ -14,9 +14,20 @@ type Payment struct { Amount float64 } +type ProductPayment struct { + Payment `alias:"pay"` +} + type Purchase struct { - Product Customer + Product + ProductPayment Total float64 taxRate float64 } + +type Person struct { + Name string `alias:"id"` + City string `alias:""` + Country string +}