[关闭]
@phper 2021-02-09T11:53:13.000000Z 字数 8911 阅读 1969

go反射实例

Golang

1. go反射结构体类型切片

  1. type Man struct {
  2. Id int
  3. Name string
  4. }
  5. s1 := make([]Man, 0)
  6. s1 = append(s1, Man{1, "a"})
  7. s1 = append(s1, Man{2, "b"})
  8. s1 = append(s1, Man{3, "c"})
  9. func(v interface{}) {
  10. getValue := reflect.ValueOf(v) // Value of v
  11. if getValue.Kind() != reflect.Slice {
  12. panic("need slice kind")
  13. }
  14. l := getValue.Len()
  15. for i := 0; i < l; i++ {
  16. value := getValue.Index(i) // Value of item
  17. typel := value.Type() // Type of item
  18. if typel.Kind() != reflect.Struct {
  19. panic("need struct kind")
  20. }
  21. fmt.Printf("type-kind: %s, type-name: %s, value: %v\n", typel.Kind(), typel.Name(), value.Interface())
  22. num := value.NumField()
  23. for j := 0; j < num; j++ {
  24. fmt.Printf("name: %s, type: %s, value: %v\n", typel.Field(j).Name, value.Field(j).Type(), value.Field(j).Interface())
  25. }
  26. fmt.Println()
  27. }
  28. }(s1)

执行打印:

  1. type-kind: struct, type-name: Man, value: {1 a}
  2. name: Id, type: int, value: 1
  3. name: Name, type: string, value: a
  4. type-kind: struct, type-name: Man, value: {2 b}
  5. name: Id, type: int, value: 2
  6. name: Name, type: string, value: b
  7. type-kind: struct, type-name: Man, value: {3 c}
  8. name: Id, type: int, value: 3
  9. name: Name, type: string, value: c

根据示例:

通过 reflect.ValueOf(v) 得到 v 的 Value 对象,它的 Len() 方法可以得到切片度;
通过 Value 对象的 Index(i) 方法得到第 i 的元素 Value 对象,然后通过 Value 对象得到 Type 对象;

值得注意的是:

Index 方法可以适用于获取 Array, Slice, or String 其中的字段
Len 方法获取长度,可以适用于 Array, Chan, Map, Slice, or String

Filed 方法用于Struct的其中字段。
NumField 方法,用于获取Struct的长度。

2. go反射结构体

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. type User struct {
  7. Id int `json:"id"`
  8. Name string `json:"name"`
  9. addr string `json:"_"`
  10. }
  11. func main(){
  12. u := User{Id:1001, Name:"aaa" , addr:"bbb"}
  13. t := reflect.TypeOf(u)
  14. v := reflect.ValueOf(u)
  15. for i := 0; i < v.NumField(); i++ {
  16. if v.Field(i).CanInterface() { //判断是否为可导出字段
  17. fmt.Printf("%s %s = %v -tag:%s n",
  18. t.Field(i).Name,
  19. t.Field(i).Type,
  20. v.Field(i).Interface(),
  21. t.Field(i).Tag)
  22. }
  23. }
  24. }

执行打印:

  1. Id int = 1001 -tag:json:"id"
  2. Name string = aaa -tag:json:"name"

:当结构体中含有非导出字段时,v.Field(i).Interface()panic, 所以使用v.Field(i).CanInterface()先判断一下

3. go反射结构体嵌套

  1. package main
  2. import (
  3. "reflect"
  4. "fmt"
  5. )
  6. type User struct {
  7. Id int
  8. Name string
  9. Address Address
  10. }
  11. type Address struct {
  12. Add string
  13. Res int
  14. }
  15. func main(){
  16. u := User{Id:1001, Name:"aaa" , Address:Address{Add:"ccccccccc", Res:12}}
  17. t := reflect.TypeOf(u)
  18. v := reflect.ValueOf(u)
  19. for i := 0; i < v.NumField(); i++ {
  20. //判断是否为可导出字段
  21. if v.Field(i).CanInterface() {
  22. //判断是否是嵌套结构
  23. if v.Field(i).Type().Kind() == reflect.Struct{
  24. structField := v.Field(i).Type()
  25. for j :=0 ; j< structField.NumField(); j++ {
  26. fmt.Printf("%s %s = %v -tag:%s \n",
  27. structField.Field(j).Name,
  28. structField.Field(j).Type,
  29. v.Field(i).Field(j).Interface(),
  30. structField.Field(j).Tag)
  31. }
  32. } else {
  33. fmt.Printf("%s %s = %v -tag:%s \n",
  34. t.Field(i).Name,
  35. t.Field(i).Type,
  36. v.Field(i).Interface(),
  37. t.Field(i).Tag)
  38. }
  39. }
  40. }
  41. }

打印:

  1. Id int = 1001 -tag:
  2. Name string = aaa -tag:
  3. Add string = ccccccccc -tag:
  4. Res int = 12 -tag:

4. 反射切片

  1. package main
  2. import (
  3. "reflect"
  4. "fmt"
  5. )
  6. func main(){
  7. var data []int
  8. data = []int{1, 2, 3, 4}
  9. //反射值
  10. v := reflect.ValueOf(data)
  11. //数组/切片长度
  12. dataNum := v.Len()
  13. for i := 0; i < dataNum; i++ {
  14. fmt.Printf("%v, ", v.Index(i).Interface())
  15. }
  16. }

打印:

  1. 1,2,3,4,

5. 通过反射将struct切片如何转换为map切片

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. type Student struct {
  7. Name string `json:"name"`
  8. Age uint `json:"age"`
  9. }
  10. type Teacher struct {
  11. Name string `json:"name"`
  12. Gender uint `json:"gender"`
  13. }
  14. // StructSliceToMapSlice : struct切片转为map切片
  15. func StructSliceToMapSlice(source interface{}) {
  16. // 判断,interface转为[]interface{}
  17. v := reflect.ValueOf(source)
  18. if v.Kind() != reflect.Slice {
  19. panic("ERROR: Unknown type, slice expected.")
  20. }
  21. l := v.Len()
  22. ret := make([]interface{}, l)
  23. for i := 0; i < l; i++ {
  24. ret[i] = v.Index(i).Interface()
  25. }
  26. // 转换之后的结果变量
  27. res := make([]map[string]interface{}, 0)
  28. // 通过遍历,每次迭代将struct转为map
  29. for _, elem := range ret {
  30. data := make(map[string]interface{})
  31. objT := reflect.TypeOf(elem)
  32. objV := reflect.ValueOf(elem)
  33. for i := 0; i < objT.NumField(); i++ {
  34. data[objT.Field(i).Name] = objV.Field(i).Interface()
  35. }
  36. res = append(res, data)
  37. }
  38. fmt.Printf("==== Convert Result ====\n%+v\n", res)
  39. }
  40. func main() {
  41. var people []interface{}
  42. // 切片添加Student元素
  43. stu1 := Student{
  44. Name: "Ame",
  45. Age: 18,
  46. }
  47. stu2 := Student{
  48. Name: "Maybe",
  49. Age: 20,
  50. }
  51. people = append(people, stu1)
  52. people = append(people, stu2)
  53. // 切片添加Teacher元素
  54. tech := Teacher{
  55. Name: "Rotk",
  56. Gender: 0,
  57. }
  58. people = append(people, tech)
  59. StructSliceToMapSlice(people)
  60. }

打印:

  1. ==== Convert Result ====
  2. [map[Age:18 Name:Ame] map[Age:20 Name:Maybe] map[Gender:0 Name:Rotk]]

6. 将map转换为struct

  1. func MapToStruct(mapData map[string]string, result interface{}) error {
  2. if reflect.ValueOf(result).Kind() != reflect.Ptr {
  3. return e.setErrorInfo(errors.New("第二参数请传指针变量!"))
  4. }
  5. if reflect.ValueOf(result).IsNil() {
  6. return e.setErrorInfo(errors.New("第二参数不能是空指针!"))
  7. }
  8. //获取元素值
  9. v := reflect.ValueOf(result).Elem()
  10. t := v.Type()
  11. //遍历结构体
  12. for i := 0; i < t.NumField(); i++ {
  13. //看下是否有sql别名
  14. sqlTag := t.Field(i).Tag.Get("sql")
  15. var fieldName string
  16. if sqlTag != "" {
  17. fieldName = strings.Split(sqlTag, ",")[0]
  18. } else {
  19. fieldName = t.Field(i).Name
  20. }
  21. //从map中取值
  22. value, ok := mapData[fieldName]
  23. if !ok {
  24. continue
  25. }
  26. switch v.Field(i).Kind() {
  27. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  28. res, err := strconv.ParseInt(value, 10, 64)
  29. if err != nil {
  30. return e.setErrorInfo(err)
  31. }
  32. v.Field(i).SetInt(res)
  33. case reflect.String:
  34. v.Field(i).SetString(value)
  35. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  36. res, err := strconv.ParseUint(value, 10, 64)
  37. if err != nil {
  38. return e.setErrorInfo(err)
  39. }
  40. v.Field(i).SetUint(res)
  41. case reflect.Float32:
  42. res, err := strconv.ParseFloat(value, 32)
  43. if err != nil {
  44. return e.setErrorInfo(err)
  45. }
  46. v.Field(i).SetFloat(res)
  47. case reflect.Float64:
  48. res, err := strconv.ParseFloat(value, 64)
  49. if err != nil {
  50. return e.setErrorInfo(err)
  51. }
  52. v.Field(i).SetFloat(res)
  53. case reflect.Bool:
  54. res, err := strconv.ParseBool(value)
  55. if err != nil {
  56. return e.setErrorInfo(err)
  57. }
  58. v.Field(i).SetBool(res)
  59. case reflect.Slice:
  60. var strArray []string
  61. var valArray []reflect.Value
  62. var valArr reflect.Value
  63. elemKind := v.Field(i).Type().Elem().Kind()
  64. elemType := t.Field(i).Type.Elem()
  65. value = strings.Trim(strings.Trim(value, "["), "]")
  66. strArray = strings.Split(value, ",")
  67. switch elemKind {
  68. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  69. for _, e := range strArray {
  70. ee, err := strconv.ParseInt(e, 10, 64)
  71. if err != nil {
  72. return err
  73. }
  74. valArray = append(valArray, reflect.ValueOf(ee).Convert(elemType))
  75. }
  76. case reflect.String:
  77. for _, e := range strArray {
  78. valArray = append(valArray, reflect.ValueOf(strings.Trim(e, "\"")).Convert(elemType))
  79. }
  80. }
  81. valArr = reflect.Append(v.Field(i), valArray...)
  82. v.Field(i).Set(valArr)
  83. }
  84. }
  85. return nil
  86. }

测试一下:

  1. m1 := map[string]string{"created": "2021-12-12", "departname": "233", "status": "2", "uid": "131733", "username":"EE2"}
  2. type User2 struct {
  3. Uid string `sql:"uid,auto_increment"`
  4. Username string `sql:"username"`
  5. Departname string `sql:"departname"`
  6. Created string `sql:"created"`
  7. Status int64 `sql:"status"`
  8. }
  9. user3 := new(User2)
  10. err := MapToStruct(m1, user3)
  11. fmt.Printf("%+v", user3)
  12. //输出: &{Uid:131733 Username:EE2 Departname:233 Created:2021-12-12 Status:2}

7. 通过反射将map切片转换为struct切片

  1. func MapSliceToStructSlice(mapSliceData []map[string]string, values interface{}) error {
  2. //原始struct的切片值
  3. destSlice := reflect.ValueOf(values).Elem()
  4. //原始单个struct的类型
  5. destType := destSlice.Type().Elem()
  6. //遍历切片
  7. for j := 0; j < len(mapSliceData); j++ {
  8. //新建1个原始struct的类型
  9. dest := reflect.New(destType).Elem()
  10. //遍历结构体
  11. for i := 0; i < destType.NumField(); i++ {
  12. //看下是否有sql别名
  13. sqlTag := destType.Field(i).Tag.Get("sql")
  14. var fieldName string
  15. if sqlTag != "" {
  16. fieldName = strings.Split(sqlTag, ",")[0]
  17. } else {
  18. fieldName = destType.Field(i).Name
  19. }
  20. //从map中取值
  21. value, ok := mapSliceData[j][fieldName]
  22. if !ok {
  23. continue
  24. }
  25. //无法赋值
  26. if !dest.Field(i).CanSet() {
  27. continue
  28. }
  29. switch dest.Field(i).Kind() {
  30. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  31. res, err := strconv.ParseInt(value, 10, 64)
  32. if err != nil {
  33. return e.setErrorInfo(err)
  34. }
  35. dest.Field(i).SetInt(res)
  36. case reflect.String:
  37. dest.Field(i).SetString(value)
  38. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  39. res, err := strconv.ParseUint(value, 10, 64)
  40. if err != nil {
  41. return e.setErrorInfo(err)
  42. }
  43. dest.Field(i).SetUint(res)
  44. case reflect.Float32:
  45. res, err := strconv.ParseFloat(value, 32)
  46. if err != nil {
  47. return e.setErrorInfo(err)
  48. }
  49. dest.Field(i).SetFloat(res)
  50. case reflect.Float64:
  51. res, err := strconv.ParseFloat(value, 64)
  52. if err != nil {
  53. return e.setErrorInfo(err)
  54. }
  55. dest.Field(i).SetFloat(res)
  56. case reflect.Bool:
  57. res, err := strconv.ParseBool(value)
  58. if err != nil {
  59. return e.setErrorInfo(err)
  60. }
  61. dest.Field(i).SetBool(res)
  62. }
  63. }
  64. //赋值
  65. destSlice.Set(reflect.Append(destSlice, dest))
  66. }
  67. return nil
  68. }

或者,我们简化一下套用上面的MapToStruct:

  1. func MapSliceToStructSlice(mapSliceData []map[string]string, values interface{}) error {
  2. //原始struct的切片值
  3. destSlice := reflect.ValueOf(values).Elem()
  4. //原始单个struct的类型
  5. destType := destSlice.Type().Elem()
  6. //遍历切片
  7. for j := 0; j < len(mapSliceData); j++ {
  8. //新建1个原始struct的类型
  9. dest := reflect.New(destType).Elem()
  10. //循环调用
  11. err := e.MapToStruct(mapSliceData[j], dest.Addr().Interface())
  12. if err != nil {
  13. return err
  14. }
  15. //赋值
  16. destSlice.Set(reflect.Append(destSlice, dest))
  17. }
  18. return nil
  19. }

测试一下:

  1. m1 := []map[string]string{{"created": "2021-12-12", "departname": "233", "status": "2", "uid": "131733", "username": "EE2"}, {"created": "2021-12-12", "departname": "233", "status": "2", "uid": "131733", "username": "EE2"}}
  2. type User2 struct {
  3. Uid int `sql:"uid,auto_increment"`
  4. Username string `sql:"username"`
  5. Departname string `sql:"departname"`
  6. Created string `sql:"created"`
  7. Status int64 `sql:"status"`
  8. }
  9. var user3 []User2
  10. err = MapSliceToStructSlice(m1, &user3)
  11. if err != nil {
  12. fmt.Println(err.Error())
  13. return
  14. }
  15. fmt.Printf("%#v", user3)

打印结果如下:

  1. []main.User2{main.User2{Uid:131733, Username:"EE2", Departname:"233", Created:"2021-12-12", Status:2}, main.User2{Uid:131733, Username:"EE2", Departname:"233", Created:"2021-12-12", Status:2}}
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注