Skip to content

Instantly share code, notes, and snippets.

@fiorix
Last active September 6, 2018 14:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fiorix/5da590addb2486e0d83cf31c6a35d46a to your computer and use it in GitHub Desktop.
Save fiorix/5da590addb2486e0d83cf31c6a35d46a to your computer and use it in GitHub Desktop.
package walkstruct
import (
"fmt"
"reflect"
"unicode"
)
// WalkStruct walks the exported fields of a struct using reflection,
// and calls fn for each field.
func WalkStruct(s interface{}, fn func(reflect.StructField, reflect.Value)) {
t := reflect.TypeOf(s)
v := reflect.ValueOf(s)
if v.Kind() == reflect.Ptr {
v = v.Elem()
t = t.Elem()
}
if v.Kind() != reflect.Struct {
panic(fmt.Sprintf("WalkStruct: s is not struct: %T", s))
}
for i := 0; i < v.NumField(); i++ {
ft := t.Field(i)
if !exportedField(ft) {
continue
}
fn(ft, v.Field(i))
}
}
func exportedField(f reflect.StructField) bool {
return !f.Anonymous && unicode.IsUpper(rune(f.Name[0]))
}
// StructFields returns the names of all exported fields of struct s.
func StructFields(s interface{}, tag string) []string {
var f []string
WalkStruct(s, func(ft reflect.StructField, fv reflect.Value) {
n := ft.Tag.Get(tag)
if n == "" {
n = ft.Name
}
f = append(f, n)
})
return f
}
// StructValues returns the values of all exported fields of struct s.
func StructValues(s interface{}) []interface{} {
var v []interface{}
WalkStruct(s, func(ft reflect.StructField, fv reflect.Value) {
v = append(v, fv.Interface())
})
return v
}
// StructValuesAddr returns pointer values of all exported fields of struct s.
func StructValuesAddr(s interface{}) []interface{} {
var v []interface{}
WalkStruct(s, func(ft reflect.StructField, fv reflect.Value) {
// this will panic if !fv.CanAddr(); and it should
v = append(v, fv.Addr().Interface())
})
return v
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment