2017-10-21 100 views
2

一个结构体的片场我有一个struct,看起来像这样:追加到使用反射

type guitaristT struct { 
    Surname string `required=true` 
    Year  int64 `required=false` 
    American bool  // example of missing tag 
    Rating float32 `required=true` 
    Styles []string `required=true,minsize=1` 
} 

我有一个环境变量,如下所示,和我使用反射来填充结构基于密钥。

jimiEnvvar :="surname=Hendrix|year=1942|american=true|rating=9.99 
    |styles=blues|styles=rock|styles=psychedelic" 

我能够设置使用反射string, int64, bool and float32领域,但我坚持就如何追加到slice样式。例如,根据上述jimiEnvvar我希望字段jimi.Styles的值为["blues","rock", "psychedelic"]

我有以下(简化的)代码:

result := guitaristT{} 
// result.Styles = make([]string, 10) // XXX causes 10 empty strings at start 
result.Styles = make([]string, 0)  // EDIT: Alessandro's solution 
... 
v := reflect.ValueOf(&result).Elem() 
... 
field := v.FieldByName(key) // eg key = "styles" 
... 
switch field.Kind() { 

case reflect.Slice: 
    // this is where I get stuck 
    // 
    // reflect.Append() has signature: 
    // func Append(s Value, x ...Value) Value 

    // so I convert my value to a reflect.Value 
    stringValue := reflect.ValueOf(value) // eg value = "blues" 

    // field = reflect.Append(field, stringValue) // XXX doesn't append 
    field.Set(reflect.Append(field, stringValue)) // EDIT: Alessandro's solution 

编辑:

的第二部分(我解决)被填充在该结构的地图。例如:

type guitaristT struct { 
    ... 
    Styles []string `required=true,minsize=1` 
    Cities map[string]int 
} 

凡jimiEnvvar样子:

case reflect.Map: 
     fmt.Println("keyAsString", keyAsString, "is Map, has value:", valueAsString) 
     mapKV := strings.Split(valueAsString, "^") 
     if len(mapKV) != 2 { 
      log.Fatalln("malformed map key/value:", mapKV) 
     } 
     mapK := mapKV[0] 
     mapV := mapKV[1] 
     thisMap := fieldAsValue.Interface().(map[string]int) 
     thisMap[mapK] = atoi(mapV) 
     thisMapAsValue := reflect.ValueOf(thisMap) 
     fieldAsValue.Set(thisMapAsValue) 

The final result was: 

main.guitaristT{ 
    Surname: "Hendrix", 
    Year:  1942, 
    American: true, 
    Rating: 9.989999771118164, 
    Styles: {"blues", "rock", "psychedelic"}, 
    Cities: {"London":11, "Bay Area":9, "New York":17, "Los Angeles":14}, 
} 

jimiEnvvar += "|cities=New York^17|cities=Los Angeles^14" 

我这样写道:如果您有兴趣,完整的代码是https://github.com/soniah/reflect/blob/master/structs.go。代码只是我正在写的一些笔记/练习。


EDIT2:

的第11章 “在实践中去”(屠夫和法里纳)有详细的反映,结构和标签说明。

回答

1

你不是太遥远。只需更换为

field.Set(reflect.Append(field, stringValue)) 

你就完成了。此外,请确保您,您使用

result.Styles = make([]string, 0) 

初始化切片或你最终将在Styles阵列的顶部具有10个空字符串。

希望这有助于您的项目,祝您好运。

+0

感谢您的回答亚历山德罗。今天,我在上面附加的地图代码上工作。它的工作原理,但也许你有一些改进它的意见? –