2017-10-21 107 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

感謝您的回答亞歷山德羅。今天,我在上面附加的地圖代碼上工作。它的工作原理,但也許你有一些改進它的意見? –