简体   繁体   English

使用反射附加到结构中的切片字段

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

I have a struct that looks like this:我有一个看起来像这样的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`
}

I have an environment variable that looks like the following, and I'm using reflection to fill the struct based on the keys.我有一个如下所示的环境变量,我使用反射来填充基于键的结构。

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

I'm able to set the string, int64, bool and float32 fields using reflection, but I'm stuck on how to append to the slice field Styles .我可以使用反射来设置string, int64, bool and float32字段,但我一直坚持如何附加到slice字段Styles For example, based on the above jimiEnvvar I would like the field jimi.Styles to have the values ["blues","rock", "psychedelic"] .例如,基于上述jimiEnvvar我想领域jimi.Styles到具有值["blues","rock", "psychedelic"]

I have the following (simplified) code:我有以下(简化)代码:

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

EDIT:编辑:

A second part (which I solved) was filling a map in the struct.第二部分(我解决了)是在结构中填充地图。 For example:例如:

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

Where jimiEnvvar looks like: jimiEnvvar 的样子:

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

I wrote in this manner:我是这样写的:

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

If you're interested the full code is at https://github.com/soniah/reflect/blob/master/structs.go .如果您有兴趣,完整代码位于https://github.com/soniah/reflect/blob/master/structs.go Code is just some notes/exercises I'm writing.代码只是我写的一些笔记/练习。


EDIT2:编辑2:

Chapter 11 of "Go in Practice" (Butcher and Farina) has detailed explanations of reflection, structs and tags. “Go in Practice”(Butcher 和 Farina)的第 11 章详细解释了反射、结构和标签。

You were not too far off.你离得太远了。 Just replace with只需替换为

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

and you are done.你就完成了。 Also, make sure you that you initialise the slice using另外,请确保您使用

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

or you will end up having 10 blank string at the top of the Styles array.否则你最终会在Styles数组的顶部有 10 个空白字符串。

Hope this helps and good luck with your project.希望这对您的项目有所帮助并祝您好运。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM