Skip to content

Instantly share code, notes, and snippets.

@Fullstop000
Created July 10, 2019 07:44
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 Fullstop000/b0241845c43aa9dfa9be0082831103be to your computer and use it in GitHub Desktop.
Save Fullstop000/b0241845c43aa9dfa9be0082831103be to your computer and use it in GitHub Desktop.
package common
import (
"fmt"
"reflect"
)
// `flatten` recursively retrieves every leaf node in a struct in depth-first fashion
// and aggregate the results into given string slice with format: "path.to.leaf = value"
// in the order of definition. Root name is ignored in the path. This helper function is
// useful to pretty-print a struct, such as configs.
// for example, given data structure:
// A{
// B{
// C: "foo",
// D: 42,
// },
// E: nil,
// }
// it should yield a slice of string containing following items:
// [
// "B.C = \"foo\"",
// "B.D = 42",
// "E =",
// ]
func Flatten(i interface{}) []string {
var res []string
flatten("", &res, reflect.ValueOf(i))
return res
}
const DELIMITER = "."
func flatten(k string, m *[]string, v reflect.Value) {
delimiter := DELIMITER
if k == "" {
delimiter = ""
}
switch v.Kind() {
case reflect.Ptr:
if v.IsNil() {
*m = append(*m, fmt.Sprintf("%s =", k))
return
}
flatten(k, m, v.Elem())
case reflect.Struct:
if x, ok := v.Interface().(fmt.Stringer); ok {
*m = append(*m, fmt.Sprintf("%s = %v", k, x))
return
}
for i := 0; i < v.NumField(); i++ {
flatten(k+delimiter+v.Type().Field(i).Name, m, v.Field(i))
}
case reflect.String:
// It is useful to quote string values
*m = append(*m, fmt.Sprintf("%s = \"%s\"", k, v))
default:
*m = append(*m, fmt.Sprintf("%s = %v", k, v))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment