You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
100 lines
2.2 KiB
Go
100 lines
2.2 KiB
Go
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
|
|
}
|