如何从interface {} value(reflection)为显式类型的struct成员设置新值? Golang

时间:2015-01-16 18:33:15

标签: database reflection interface go

我想了解使用反射包的一些微妙时刻。请看下面的例子,它更好地描述了我想知道的事情:

type Robot struct {
    id    int
    model string
}

func change(i interface{}, fields ...string) {
        v := reflect.ValueOf(i).Elem()
        // here I emulate function by slice that could return any value,
        // so here I need to check if I can store incoming values to existing struct
        returns := []interface{}{100, "Something"}
        for i, name := range fields {
            x := reflect.ValueOf(&returns[i]).Elem()
            //check if value representing x is the same of struct member
            v.FieldByName(name).Set(x)
            // ^ here I want to store 100 to Robot.id when i = 0,
            // and "Something" to Robot.model when i = 1
        }


}

func main() {
    robot := &Robot{id: 1, model: "T310"}
    change(robot, "model", "id")
    // now robot become as follows: &Robot{100, "Something"}
}

为什么需要?

    // It is need for retrieving values from sql DB into struct members 
    // (only for training purposes :))
    // Example:
    f := func(q string, structs interface{}, fields ...string) {
        rows, _ := db.Query(q)
        for i := 0; rows.Next(); i++ {
            rows.Scan(&structs[i])
            // very dirty here! it's hard to understand how to implement it
        }
    }
    var robots = []*Robot
    f("select id, model from robots", robots, "id", "model")
    // now each member of robots var should contain values from DB

我试图描述并尽可能简短地解释。我希望你理解我..

1 个答案:

答案 0 :(得分:1)

您只能通过反射设置导出的字段,因此请先将其大写。否则,如果您指望位置值,请确保它们已正确对齐。

例如:http://play.golang.org/p/ItnjwwJnxe

type Robot struct {
    ID    int
    Model string
}

func change(i interface{}, fields ...string) {
    returns := []interface{}{100, "Something"}

    v := reflect.ValueOf(i).Elem()
    for i, name := range fields {
        val := reflect.ValueOf(returns[i])
        v.FieldByName(name).Set(val)
    }
}

func main() {
    robot := &Robot{ID: 1, Model: "T310"}
    fmt.Println(robot)
    change(robot, "ID", "Model")
    fmt.Println(robot)
}