How do I set a dynamic structure field in Go?

I am parsing JSON in Go in map[string]interface{}

and using the mixed string, float and slice interface values ​​to populate the structure field values PlaceNode

.

I need something like "default values" because not all JSON objects have all Struct fields. Coming from other language backgrounds, there were indexed Struct that I would use to do something like this to set a value in a variable n Placenode

(for example, as if it were a keyword self

or this

in JavaScript).

n[key] = value;

      

Instead, I have a method in my structure PlaceNode

to read interface{}

, use reflect

and optionally assign a value if the field can be set. Mine interfaces{}

does not implement all values ​​and therefore I am having problems with unmarshmaling directly in my framework.

Apparently, none of the fields are validating s.CanSet()

. So I have to go about it wrong.

How do I set a dynamic structure 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 argument data

map[string]interface{}

has an interface that is also 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
   }
 }

      

+3


source to share


1 answer


When making the next call:

st := reflect.ValueOf(n)

      

ValueOf

a copy of the structure is passed PlaceNode

. Therefore, any changes made to st

will not show up in n

. For this reason, the package treats such cases as unaddressed values. If you want reflect.Value

which represents n

, try using something like this:



st := reflect.ValueOf(&n).Elem()

      

Now st

works directly with n

, not a copy, and is addressed. Now you have to use different methods Set*

and its fields.

+8


source







All Articles