Go: How can I "unpack" a struct?

huangapple go评论120阅读模式
英文:

Go: How can I "unpack" a struct?

问题

我有一个结构体:

  1. type mystruct struct {
  2. Foo string
  3. Bar int
  4. }

我想从这个结构体创建以下形式的SQL插入语句:

  1. m := mystruct{"Hello", 1}
  2. query := "INSERT INTO mytbl (foo, bar) VALUES (?, ?)"
  3. res, err := db.Exec(query, m.Foo, m.Bar)

现在我的问题是:如何根据结构体(或m本身)动态生成最后一行代码?我可以使用reflect获取结构体的字段名,但我不知道如何为db.Exec()调用创建[]interface{}切片。这是我尝试过的代码:(http://play.golang.org/p/GR1Bb61NFH)

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. type mystruct struct {
  7. Foo string
  8. Bar int
  9. }
  10. func main() {
  11. m := mystruct{"Foo", 1}
  12. fmt.Println(readNames(m))
  13. x := unpackStruct(m)
  14. fmt.Printf("%#v\n", x)
  15. }
  16. func unpackStruct(a interface{}) []interface{} {
  17. // 将a转换为m类型
  18. // 不起作用,来自“反射定律”
  19. s := reflect.ValueOf(&t).Elem()
  20. typeOfT := s.Type()
  21. for i := 0; i < s.NumField(); i++ {
  22. f := s.Field(i)
  23. fmt.Printf("%d: %s %s = %v\n", i,
  24. typeOfT.Field(i).Name, f.Type(), f.Interface())
  25. }
  26. // 这是我想要的原则:
  27. m := mystruct{"Hello", 2}
  28. var ret []interface{}
  29. ret = make([]interface{}, s.NumField())
  30. ret[0] = m.Foo
  31. ret[1] = m.Bar
  32. return ret
  33. }
  34. // 运行良好:
  35. func readNames(a interface{}) []string {
  36. s := reflect.TypeOf(a)
  37. lenStruct := s.NumField()
  38. ret := make([]string, lenStruct)
  39. for i := 0; i < lenStruct; i++ {
  40. ret[i] = s.Field(i).Name
  41. }
  42. return ret
  43. }
英文:

I have a struct:

  1. type mystruct struct {
  2. Foo string
  3. Bar int
  4. }

I'd like to create SQL insert statements from the struct which have the following form:

  1. m := mystruct{ &quot;Hello&quot; , 1 }
  2. query := &quot;INSERT INTO mytbl ( foo, bar ) VALUES ( ?,? )&quot;
  3. res,err := db.Exec(query, m.Foo, m.Bar)

Now my question is: how can I make the last line dynamically from the struct (or m) itself? I am able to get the struct names using reflect, but I don't know how to create the []interface{} slice for the db.Exec() call. This is what I have tried: (http://play.golang.org/p/GR1Bb61NFH)

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;reflect&quot;
  5. )
  6. type mystruct struct {
  7. Foo string
  8. Bar int
  9. }
  10. func main() {
  11. m := mystruct{&quot;Foo&quot;, 1}
  12. fmt.Println(readNames(m))
  13. x := unpackStruct(m)
  14. fmt.Printf(&quot;%#v\n&quot;, x)
  15. }
  16. func unpackStruct(a interface{}) []interface{} {
  17. // &quot;convert&quot; a to m t
  18. // doesn&#39;t work, from &#39;laws of reflection&#39;
  19. s := reflect.ValueOf(&amp;t).Elem()
  20. typeOfT := s.Type()
  21. for i := 0; i &lt; s.NumField(); i++ {
  22. f := s.Field(i)
  23. fmt.Printf(&quot;%d: %s %s = %v\n&quot;, i,
  24. typeOfT.Field(i).Name, f.Type(), f.Interface())
  25. }
  26. // this is in principle what I want:
  27. m := mystruct{&quot;Hello&quot;, 2}
  28. var ret []interface{}
  29. ret = make([]interface{}, s.NumField())
  30. ret[0] = m.Foo
  31. ret[1] = m.Bar
  32. return ret
  33. }
  34. // works fine:
  35. func readNames(a interface{}) []string {
  36. s := reflect.TypeOf(a)
  37. lenStruct := s.NumField()
  38. ret := make([]string, lenStruct)
  39. for i := 0; i &lt; lenStruct; i++ {
  40. ret[i] = s.Field(i).Name
  41. }
  42. return ret
  43. }

答案1

得分: 2

如果你的问题是获取字段的值,以下代码片段应该能帮到你:

  1. s := reflect.ValueOf(a)
  2. ret := make([]interface{}, s.NumField())
  3. for i := 0; i < s.NumField(); i++ {
  4. ret[i] = s.Field(i).Interface()
  5. }
英文:

If getting the values of the fields is your issue, this code snippet should help:

  1. s := reflect.ValueOf(a)
  2. ret := make([]interface{}, s.NumField())
  3. for i := 0; i &lt; s.NumField(); i++ {
  4. ret[i] = s.Field(i).Interface()
  5. }

答案2

得分: 0

如果创建[]interface{}值是你的问题,使用reflect的切片创建机制应该能很好地解决:

  1. slc := reflect.MakeSlice(InterfaceType, len, cap) // 请参考下面的链接来创建InterfaceType
  2. slc.Index(0).Set(TargetValue)
  3. return slc.Interface()

(这是上述提到的链接)。

修改上述代码以循环遍历结构体中的值而不仅仅是第0个索引应该不会太麻烦。

英文:

If creating the []interface{} value is your problem, using reflect's slice creation mechanisms should work nicely:

  1. slc := reflect.MakeSlice(InterfaceType, len, cap) // See the link below for creating InterfaceType
  2. slc.Index(0).Set(TargetValue)
  3. return slc.Interface()

(Here's the above-mentioned link).

Modifying the above code to loop over the values in the struct instead of just the 0th index shouldn't be too bad.

huangapple
  • 本文由 发表于 2013年9月5日 14:04:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/18628852.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定