通过反射修改结构体字段值

代码

需要转入 指针 类型, 并调用 Elem() 方法 转化, 然后调用 SetXxx() 方法修改属性值

  1. // 运用反射 修改 结构体 字段 案例
  2. // 反射可以用来开发底层框架
  3. package main
  4. import (
  5. "encoding/json"
  6. "fmt"
  7. "reflect"
  8. )
  9. // 这就需要通过 tag 来转化大写的字段,同时又保证内部调用的时候可以暴露变量
  10. // 反射原理
  11. type People struct {
  12. Name string `json:"name01"`
  13. Age int `json:"age"`
  14. Height float64 `json:"height"`
  15. Action string
  16. }
  17. // 给结构体绑定方法
  18. func (p People) Print() {
  19. fmt.Println("print() = ", p)
  20. }
  21. func (p People) GetSum(n1, n2 int) int {
  22. return n1 + n2
  23. }
  24. func (p People) Set(name string, age int, height float64, action string) {
  25. p.Name = name
  26. p.Age = age
  27. p.Height = height
  28. p.Action = action
  29. }
  30. func TestStruct(a interface{}) {
  31. typ := reflect.TypeOf(a)
  32. val := reflect.ValueOf(a)
  33. kd := val.Kind()
  34. if kd != reflect.Ptr && val.Elem().Kind() == reflect.Struct {
  35. fmt.Println("except struct, but its not")
  36. return
  37. }
  38. // 结构体字段
  39. // 字段的顺序跟定义结构体时字段的先后顺序一致
  40. num := val.Elem().NumField()
  41. fmt.Printf("struct has %v fields \n", num)
  42. for i := 0; i < num; i++ {
  43. fmt.Printf("第%v个字段:%v \n", i+1, val.Elem().Field(i))
  44. tagVal := typ.Elem().Field(i).Tag.Get("json")
  45. if tagVal != "" {
  46. fmt.Printf("第%v个字段, tag : %v \n", i+1, tagVal)
  47. }
  48. }
  49. // 结构体方法
  50. numOfMethod := val.NumMethod()
  51. fmt.Printf("struct 有 %v 个方法 \n", numOfMethod)
  52. // 内部方法名顺序,按照函数名的 ascii 码排序的
  53. val.Method(1).Call(nil)
  54. var params []reflect.Value
  55. params = append(params, reflect.ValueOf(10))
  56. params = append(params, reflect.ValueOf(40))
  57. res := val.Method(0).Call(params)
  58. fmt.Println("res = ", res[0].Int())
  59. // 修改结构体字段值
  60. val.Elem().Field(1).SetInt(20)
  61. }
  62. func main() {
  63. // struct
  64. p1 := People{
  65. Name: "tom",
  66. Age: 18,
  67. Height: 178.5,
  68. Action: "衣食住行",
  69. }
  70. // 序列化就是通过反射机制获取到 tag 值
  71. p1Str, err := json.Marshal(p1)
  72. if err != nil {
  73. fmt.Println("序列化失败", err)
  74. } else {
  75. fmt.Println("p1Str = ", string(p1Str))
  76. }
  77. // 传入指针类型, 调用 Elem() 和 SetXxx()
  78. TestStruct(&p1)
  79. fmt.Println("p1 = ", p1)
  80. }
  81. /*
  82. print() = {tom 18 178.5 衣食住行}
  83. p1 = {tom 20 178.5 衣食住行}
  84. */

使用反射机制,编写函数适配器,桥连接

reflect_test.go 单元测试

代码

  1. // reflect_test.go 单元测试
  2. // 使用反射机制,编写适配器函数 桥连接
  3. package test
  4. import (
  5. "reflect"
  6. "testing"
  7. )
  8. // type User struct {
  9. // UserId string
  10. // Name string
  11. // }
  12. func TestReflectFunc(t *testing.T) {
  13. // 定义两个不同参数的函数
  14. call1 := func(v1 int, v2 int) {
  15. t.Log(v1, v2)
  16. }
  17. call2 := func(v1 int, v2 int, s string) {
  18. t.Log(v1, v2, s)
  19. }
  20. var (
  21. function reflect.Value
  22. inValue []reflect.Value
  23. n int
  24. )
  25. bridge := func(call interface{}, args ...interface{}) {
  26. n = len(args)
  27. inValue = make([]reflect.Value, n)
  28. for i := 0; i < n; i++ {
  29. inValue[i] = reflect.ValueOf(args[i])
  30. }
  31. function = reflect.ValueOf(call)
  32. // len(in) == 3, v.Call(in)代表调用v(in[0], in[1], in[2])
  33. function.Call(inValue)
  34. }
  35. bridge(call1, 1, 2)
  36. bridge(call2, 1, 2, "test2")
  37. }
  38. /*
  39. go test -v
  40. === RUN TestReflectFunc
  41. reflect_test.go:17: 1 2
  42. reflect_test.go:20: 1 2 test2
  43. --- PASS: TestReflectFunc (0.00s)
  44. PASS
  45. ok go_code/reflect/reflect04/main 0.545s
  46. */

通过反射创建并操作结构体

代码

  1. // reflect_test.go 测试用例
  2. // 通过反射创建并操作结构体
  3. package test
  4. import (
  5. "reflect"
  6. "testing"
  7. )
  8. type User struct {
  9. UserId string
  10. Name string
  11. }
  12. func TestReflectStructPtr(t *testing.T) {
  13. var (
  14. model *User
  15. st reflect.Type
  16. elem reflect.Value
  17. )
  18. // 获取 *User 类型
  19. st = reflect.TypeOf(model)
  20. t.Log("reflect.TypeOf = ", st.Kind().String()) // ptr
  21. // st 真正指向的类型
  22. st = st.Elem()
  23. t.Log("reflect.TypeOf.Elem = ", st.Kind().String()) // struct
  24. // New 返回一个 Value 类型的值,该值持有一个指向类型为 typ 的新申请的零值的指针
  25. elem = reflect.New(st)
  26. t.Log("reflect.New", elem.Kind().String()) // ptr
  27. t.Log("reflect.New.Elem", elem.Elem().Kind().String()) // struct
  28. // model 就是创建的 User 结构体变量(实例)
  29. // 类型断言
  30. model = elem.Interface().(*User) // model 是 *User, 它的指向跟elem 是一样的
  31. elem = elem.Elem() // 取得 elem 指向的值
  32. // 结构体赋值
  33. elem.FieldByName("UserId").SetString("123456")
  34. elem.FieldByName("Name").SetString("xiao")
  35. t.Log("model model.Name", model, model.Name)
  36. }
  37. /*
  38. go test -v
  39. === RUN TestReflectStructPtr
  40. reflect_test.go:24: reflect.TypeOf = ptr
  41. reflect_test.go:27: reflect.TypeOf.Elem = struct
  42. reflect_test.go:30: reflect.New ptr
  43. reflect_test.go:31: reflect.New.Elem struct
  44. reflect_test.go:39: model model.Name &{123456 xiao} xiao
  45. --- PASS: TestReflectStructPtr (0.00s)
  46. PASS
  47. ok go_code/reflect/reflect05/test 0.740s
  48. */