map[string]interface{}
Using the reflect package of Golang, we can inspect the field inside a certain struct and obtain
the field name and value to be converted into map[string]interface{}
type SimpleStruct struct {
AString string `json:"aString"`
}
structed := SimpleStruct{"hehe"}
reflectedValue := reflect.ValueOf(structed)
reflectedType := reflect.TypeOf(structed)
log.Printf("Struct was named: %s", reflectedType.Name())
log.Printf("First field was named: %s", reflectedType.Field(0).Name)
log.Printf("First field has value: %s", reflectedValue.Field(0).Interface())
Some important reflect functions includes:
CanInterface()
: to check if we can pick value out of the reflected variablevalue.Kind() == reflect.Pointer
: to check if the reflected value is a pointer or notvalue.Elem().Interface()
: to get the pointed value of a pointer variablenil
pointer or not to avoid accessing inexistent pointertype.NumField()
: to get the number of fields in the struct. We will be using this to iterate through the fields in the structThe general idea of this struct to map function is to:
Always resolve pointer variables. If the variable is a nil
pointer, assign nil
to the map as well. e.g.
var maybeNil *T
reflectedMaybeNil := reflect.ValueOf(maybeNil)
if maybePointer == nil {
outMap[fieldName] = nil
return
}
value := reflectedMaybeNil.Elem().Interface()
outMap[fieldname] = value
Recursively apply struct to map function if the value is a struct or an element of an array is a struct. A simple reflect.Kind
check can help us.
value := reflect.Valueof(someVarHere)
if value.Kind() == reflect.Struct {
outmap[fieldName] = StructToMap(value)
}
var array []interface{}
if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
array := value.Interface().([]interface{})
var outValue = make([]interface{}, len(array))
for index, rawValue := range array {
// check if struct or array here, call StructToMap as required
}
}
The full gist can be found here: https://gist.github.com/ye-yu/0e4c39fb1eee5b791d2768841f87753c
In this gist, I inspect the field name by the struct tag (if empty, I default it back to the original field name). I also add ,inline
feature to allow fields to be populate from the parent map instead.