使用反射将数据追加到结构体中的切片字段

8

我有一个看起来像这样的结构体

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、boolfloat32 字段,但我不知道如何向 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语言实战》(Butcher和Farina)的第11章详细介绍了反射、结构体和标签。

1个回答

3
你的理解并没有太偏离。只需要替换为即可。
field.Set(reflect.Append(field, stringValue)) 

然后你就完成了。另外,请确保使用以下方式初始化切片:

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

否则您会在Styles数组的顶部得到10个空字符串。
希望这可以帮助你,祝你的项目好运。

谢谢你的回答,Alessandro。今天我在地图代码上工作了,如上所示。它可以运行,但你可能有一些改进意见吗? - Sonia Hamilton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接