package reflection import "reflect" // Go allows for `interface{}` which we can think as as just // any type. (any is just an alias for interface{}) this allows for // some metaprogramming features in the language reflection being one // of them. Reflection allows us to examine structure at runtime. // The downside, you lose type safety and performance impact. // Only use reflection if you really need to. // See also https://blog.golang.org/laws-of-reflection func walk(x interface{}, fn func(input string)) { // This code is very unsafe and very naive, val := getValue(x) // if val.Kind() == reflect.Slice { // for i := 0; i < val.Len(); i++ { // walk(val.Index(i).Interface(), fn) // } // return // } // // This would panic if there were no fields // field := val.Field(0) // // This would be wrong if the field had any value other than a string // fn(field.String()) // // change for test table ( will fail case 2) // for i := 0; i < val.NumField(); i++ { // field := val.Field(i) // fn(field.String()) // } // THIS GOT messy // for i := 0; i < val.NumField(); i++ { // field := val.Field(i) // // if field.Kind() == reflect.String { // // fn(field.String()) // // } // // if field.Kind() == reflect.Struct { // // // it got recursive // // walk(field.Interface(), fn) // // } // switch field.Kind() { // case reflect.String: // fn(field.String()) // case reflect.Struct: // walk(field.Interface(), fn) // } // } switch val.Kind() { case reflect.Struct: for i := 0; i < val.NumField(); i++ { walk(val.Field(i).Interface(), fn) } case reflect.Slice, reflect.Array: for i := 0; i < val.Len(); i++ { walk(val.Index(i).Interface(), fn) } case reflect.Map: for _, key := range val.MapKeys() { walk(val.MapIndex(key).Interface(), fn) } case reflect.Chan: for { if v, ok := val.Recv(); ok { walk(v.Interface(), fn) } else { break } } case reflect.Func: valFnResult := val.Call(nil) for _, res := range valFnResult { walk(res.Interface(), fn) } case reflect.String: fn(val.String()) } } func getValue(x interface{}) reflect.Value { val := reflect.ValueOf(x) if val.Kind() == reflect.Pointer { val = val.Elem() } return val }