I'm unmarshalling JSON in Go to a map[string]interface{} and using the interface's mixed string, float and slice values to populate field values of a PlaceNode struct.
I need something like "Default values" because not all JSON objects have all Struct fields. Coming from other language backgrounds, were Structs indexable I'd be used to doing something like this to set a value on the n Placenode variable (e.g. as if it were a self or this keyword in JavaScript).
n[key] = value;
Instead, I have a method on my PlaceNode struct to read the interface{}, use reflect and optionally assign a value if the field can be set. My interfaces{} don't implement all values and so I'm having trouble unmarshmaling directly into my struct.
Apparently none of the fields pass this s.CanSet() check. So I must be going about this wrong.
How do I set a dynamic struct field in Go?
func (n PlaceNode) New(data map[string]interface{}) PlaceNode {
for key, val := range data {
n.Id = key
for k, v := range val.(map[string]interface{}) {
f := reflect.ValueOf(v)
st := reflect.ValueOf(n)
if (st.Kind() == reflect.Struct) {
s := st.FieldByName(k)
if f.Kind() == reflect.String && true == s.CanSet() {
s.SetString(f.String());
} else if f.Kind() == reflect.Float64 && true == s.CanSet() {
s.SetFloat(f.Float());
} else if f.Kind() == reflect.Slice && true == s.CanSet() {
s.Set(f.Slice(0, f.Len()));
}
}
}
}
return n
}
The data argument map[string]interface{} has an interface that is also a map[string]interface{} and looks like this:
{
"XV.12A": {
"Area": 1189.132667,
"CensusBlock": 2032,
"CensusBlockGroup": 2,
"CensusCbsaFips": 40900,
"CensusCountyFips": 61,
"CensusMcdFips": 90160,
"CensusMsaFips": 6922,
"CensusPlaceFips": 3204,
"CensusStateFips": 6,
"CensusTract": 203,
"CensusYear": 2010,
"Radius": 19.455402434548,
"RegionSize": 1189.132667
}
}