如何在Go中设置动态结构字段?

bul*_*ley 3 go

我在Go to a中解组JSON map[string]interface{}并使用接口的混合字符串,float和slice值来填充PlaceNode结构的字段值.

我需要类似"默认值"的东西,因为并非所有JSON对象都具有所有Struct字段.来自其他语言背景,Structs是可索引的我会习惯做这样的事情来设置n Placenode变量的值(例如,好像它是JavaScript 中的一个selfthis关键字).

n[key] = value;
Run Code Online (Sandbox Code Playgroud)

相反,我在我的PlaceNodestruct 上有一个方法来读取interface{},使用reflect并可选地分配一个值,如果可以设置该字段.我interfaces{}没有实现所有的值,所以我很难直接进入我的结构.

显然没有一个字段通过此s.CanSet()检查.所以我一定是在犯这个错误.

如何在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
}
Run Code Online (Sandbox Code Playgroud)

data参数map[string]interface{}的接口也是a map[string]interface{},如下所示:

  {
   "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
   }
 }
Run Code Online (Sandbox Code Playgroud)

Jam*_*dge 8

当您拨打以下电话时:

st := reflect.ValueOf(n)
Run Code Online (Sandbox Code Playgroud)

ValueOf传递PlaceNode结构的副本.所以所做的任何改变st都不会被看到n.因此,包将此类情况视为不可寻址的值.如果你想要一个reflect.Value代表n,请尝试使用这样的东西:

st := reflect.ValueOf(&n).Elem()
Run Code Online (Sandbox Code Playgroud)

现在st直接使用n而不是副本,并且是可寻址的.您现在应该可以使用Set*它及其字段的各种方法.