簡體   English   中英

使用反射附加到結構中的切片字段

[英]Append to a slice field in a struct using reflection

我有一個看起來像這樣的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字段Styles 例如,基於上述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 的樣子:

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

我是這樣寫的:

    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},
}

如果您有興趣,完整代碼位於https://github.com/soniah/reflect/blob/master/structs.go 代碼只是我寫的一些筆記/練習。


編輯2:

“Go in Practice”(Butcher 和 Farina)的第 11 章詳細解釋了反射、結構和標簽。

你離得太遠了。 只需替換為

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

你就完成了。 另外,請確保您使用

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

否則你最終會在Styles數組的頂部有 10 個空白字符串。

希望這對您的項目有所幫助並祝您好運。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM