1. 反射

反射是指在程序运行期对程序本身进行访问和修改的能力

1.1.1. 变量的内在机制

  • 变量包含类型信息和值信息 var arr [10]int arr[0] = 10
  • 类型信息:是静态的元信息,是预先定义好的
  • 值信息:是程序运行过程中动态改变的

1.1.2. 反射的使用

  • reflect包封装了反射相关的方法
  • 获取类型信息:reflect.TypeOf,是静态的
  • 获取值信息:reflect.ValueOf,是动态的

1.1.3. 空接口与反射

  • 反射可以在运行时动态获取程序的各种详细信息
  • 反射获取interface类型信息
  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. //反射获取interface类型信息
  7. func reflect_type(a interface{}) {
  8. t := reflect.TypeOf(a)
  9. fmt.Println("类型是:", t)
  10. // kind()可以获取具体类型
  11. k := t.Kind()
  12. fmt.Println(k)
  13. switch k {
  14. case reflect.Float64:
  15. fmt.Printf("a is float64\n")
  16. case reflect.String:
  17. fmt.Println("string")
  18. }
  19. }
  20. func main() {
  21. var x float64 = 3.4
  22. reflect_type(x)
  23. }
  • 反射获取interface值信息
  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. //反射获取interface值信息
  7. func reflect_value(a interface{}) {
  8. v := reflect.ValueOf(a)
  9. fmt.Println(v)
  10. k := v.Kind()
  11. fmt.Println(k)
  12. switch k {
  13. case reflect.Float64:
  14. fmt.Println("a是:", v.Float())
  15. }
  16. }
  17. func main() {
  18. var x float64 = 3.4
  19. reflect_value(x)
  20. }
  • 反射修改值信息
  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. //反射修改值
  7. func reflect_set_value(a interface{}) {
  8. v := reflect.ValueOf(a)
  9. k := v.Kind()
  10. switch k {
  11. case reflect.Float64:
  12. // 反射修改值
  13. v.SetFloat(6.9)
  14. fmt.Println("a is ", v.Float())
  15. case reflect.Ptr:
  16. // Elem()获取地址指向的值
  17. v.Elem().SetFloat(7.9)
  18. fmt.Println("case:", v.Elem().Float())
  19. // 地址
  20. fmt.Println(v.Pointer())
  21. }
  22. }
  23. func main() {
  24. var x float64 = 3.4
  25. // 反射认为下面是指针类型,不是float类型
  26. reflect_set_value(&x)
  27. fmt.Println("main:", x)
  28. }

1.1.4. 结构体与反射

查看类型、字段和方法

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. // 定义结构体
  7. type User struct {
  8. Id int
  9. Name string
  10. Age int
  11. }
  12. // 绑方法
  13. func (u User) Hello() {
  14. fmt.Println("Hello")
  15. }
  16. // 传入interface{}
  17. func Poni(o interface{}) {
  18. t := reflect.TypeOf(o)
  19. fmt.Println("类型:", t)
  20. fmt.Println("字符串类型:", t.Name())
  21. // 获取值
  22. v := reflect.ValueOf(o)
  23. fmt.Println(v)
  24. // 可以获取所有属性
  25. // 获取结构体字段个数:t.NumField()
  26. for i := 0; i < t.NumField(); i++ {
  27. // 取每个字段
  28. f := t.Field(i)
  29. fmt.Printf("%s : %v", f.Name, f.Type)
  30. // 获取字段的值信息
  31. // Interface():获取字段对应的值
  32. val := v.Field(i).Interface()
  33. fmt.Println("val :", val)
  34. }
  35. fmt.Println("=================方法====================")
  36. for i := 0; i < t.NumMethod(); i++ {
  37. m := t.Method(i)
  38. fmt.Println(m.Name)
  39. fmt.Println(m.Type)
  40. }
  41. }
  42. func main() {
  43. u := User{1, "zs", 20}
  44. Poni(u)
  45. }

查看匿名字段

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. // 定义结构体
  7. type User struct {
  8. Id int
  9. Name string
  10. Age int
  11. }
  12. // 匿名字段
  13. type Boy struct {
  14. User
  15. Addr string
  16. }
  17. func main() {
  18. m := Boy{User{1, "zs", 20}, "bj"}
  19. t := reflect.TypeOf(m)
  20. fmt.Println(t)
  21. // Anonymous:匿名
  22. fmt.Printf("%#v\n", t.Field(0))
  23. // 值信息
  24. fmt.Printf("%#v\n", reflect.ValueOf(m).Field(0))
  25. }

修改结构体的值

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. // 定义结构体
  7. type User struct {
  8. Id int
  9. Name string
  10. Age int
  11. }
  12. // 修改结构体值
  13. func SetValue(o interface{}) {
  14. v := reflect.ValueOf(o)
  15. // 获取指针指向的元素
  16. v = v.Elem()
  17. // 取字段
  18. f := v.FieldByName("Name")
  19. if f.Kind() == reflect.String {
  20. f.SetString("kuteng")
  21. }
  22. }
  23. func main() {
  24. u := User{1, "5lmh.com", 20}
  25. SetValue(&u)
  26. fmt.Println(u)
  27. }

调用方法

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. // 定义结构体
  7. type User struct {
  8. Id int
  9. Name string
  10. Age int
  11. }
  12. func (u User) Hello(name string) {
  13. fmt.Println("Hello:", name)
  14. }
  15. func main() {
  16. u := User{1, "5lmh.com", 20}
  17. v := reflect.ValueOf(u)
  18. // 获取方法
  19. m := v.MethodByName("Hello")
  20. // 构建一些参数
  21. args := []reflect.Value{reflect.ValueOf("6666")}
  22. // 没参数的情况下:var args2 []reflect.Value
  23. // 调用方法,需要传入方法的参数
  24. m.Call(args)
  25. }

获取字段的tag

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. type Student struct {
  7. Name string `json:"name1" db:"name2"`
  8. }
  9. func main() {
  10. var s Student
  11. v := reflect.ValueOf(&s)
  12. // 类型
  13. t := v.Type()
  14. // 获取字段
  15. f := t.Elem().Field(0)
  16. fmt.Println(f.Tag.Get("json"))
  17. fmt.Println(f.Tag.Get("db"))
  18. }

1.1.5. 反射练习

  • 任务:解析如下配置文件
    • 序列化:将结构体序列化为配置文件数据并保存到硬盘
    • 反序列化:将配置文件内容反序列化到程序的结构体
  • 配置文件有server和mysql相关配置
  1. #this is comment
  2. ;this a comment
  3. ;[]表示一个section
  4. [server]
  5. ip = 10.238.2.2
  6. port = 8080
  7. [mysql]
  8. username = root
  9. passwd = admin
  10. database = test
  11. host = 192.168.10.10
  12. port = 8000
  13. timeout = 1.2

代码地址:https://github.com/lu569368/Practise_reflex.git