• Go语言入门心法(十三): 反射认知升维



    Go语言入门心法(一): 基础语法

    Go语言入门心法(二): 结构体

    Go语言入门心法(三): 接口

    Go语言入门心法(四): 异常体系

     Go语言入门心法(五): 函数

    Go语言入门心法(六): HTTP面向客户端|服务端编程

    Go语言入门心法(七): 并发与通道

    Go语言入门心法(八): mysql驱动安装报错onnection failed

    Go语言入门心法(九): 引入三方依赖

    Go语言入门心法(十):Go语言操作MYSQL(CRUD)|事务处理

    Go语言入门心法(十一): 文件处理

     Go语言入门心法(十二): GORM映射框架

    Go语言入门心法(十三): 反射认知升维

    Go语言入门心法(十四): Go操作Redis实战




     一: go语言反射认知

    反射的强大之处就在于它非常灵活,通常用于做通用框架代码,而不需要理解业务,因此不需要具有快速处理不同业务的功能,但是强大的同时也带来了很多弊端;
    比如其代码可读性和可维护性变差,性能也大打折扣;是否需要使用反射需进行利弊权衡,并不是所有的程序都适合使用反射;
       (1)go语言提供了一种反射的机制: 在运行时需要检查或者更新变量的值,并调用动态调用其方法和它们支持的内在操作,而这些操作在编译时并不知道这些变量的
       具体类型;而这种动态操作变量对象的方式就成为反射机制;
       (2)变量的类型通常分为:
          2.1 静态类型,即是在定义变量时指定的具体类型,或者在编译时就可以确定的类型
          2.2 动态类型,需要程序运行状态下才能确认的类型,如对应一个接口,有多个子接口,通常我们可以使用父接口作为数据类型定义该接口类型的变量对象,
          这时这个变量对象的值可以是该接口子实现类型的接口,具体是那一个需在运行过程中动态感知;
          2.3 类别Java语言,通过反射机制在运行时能够做到下面的几点
              2.3.1 确认对象的类
              2.3.2 确认类的所有成员变量和方法
              2.3.3 动态调用任意一个方法和变量
       (3)go语言中,只能使用一种方式来获取运行状态的对象的值或者方法,最重要的是,Go语言不支持通过字符串解析,从而反射出对应的类型结构,这点与java有着很大的区别
    


    反射实例一:


    1. package main
    2. import (
    3. "fmt"
    4. "reflect"
    5. )
    6. /*
    7. go语言中反射认知:
    8. 反射的强大之处就在于它非常灵活,通过用于做通用框架代码,而不需要理解业务,因此不需要具有快速处理不同业务的功能,但是强大的同时也带来了很多弊端;
    9. 比如其代码可读性和可维护性变差,性能也大打折扣;是否需要使用反射需进行利弊权衡,并不是所有的程序都适合使用反射;
    10. (1)go语言提供了一种反射的机制: 在运行时需要检查或者更新变量的值,并调用动态调用其方法和它们支持的内在操作,而这些操作在编译时并不知道这些变量的
    11. 具体类型;而这种动态操作变量对象的方式就成为反射机制;
    12. (2)变量的类型通常分为:
    13. 2.1 静态类型,即是在定义变量时指定的具体类型,或者在编译时就可以确定的类型
    14. 2.2 动态类型,需要程序运行状态下才能确认的类型,如对应一个接口,有多个子接口,通常我们可以使用父接口作为数据类型定义该接口类型的变量对象,
    15. 这时这个变量对象的值可以该接口子实现类型的接口,具体是那一个需在运行过程中动态感知;
    16. 2.3 类别Java语言,通过反射机制在运行时能够做到下面的几点
    17. 2.3.1 确认对象的类
    18. 2.3.2 确认类的所有成员变量和方法
    19. 2.3.3 动态调用任意一个方法和变量
    20. (3)go语言中,只能使用一种方式来获取运行状态的对象的值或者方法,最重要的是,Go语言不支持通过字符串解析,从而反射出对应的类型结构,这点与java有着很大的区别
    21. */
    22. func main() {
    23. var result interface{} = "这是测试反射的第一个例子"
    24. typeOfResult := reflect.TypeOf(result)
    25. println("========================-获取变量result的类型===============")
    26. fmt.Printf("变量的静态类型为:%s", "interface{}")
    27. println("在变量运行状态下获取result变量的类型为:\n ", typeOfResult.Name())
    28. println("==========================动态获取变量result的值=============\n")
    29. if typeOfResult.Kind() == reflect.String {
    30. fmt.Printf("变量的值为: %s", typeOfResult.String())
    31. }
    32. println(`
    33. 下面来看下kind的源代码:
    34. type Kind uint
    35. const (
    36. Invalid Kind = iota
    37. Bool
    38. Int
    39. Int8
    40. Int16
    41. Int32
    42. Int64
    43. Uint
    44. Uint8
    45. Uint16
    46. Uint32
    47. Uint64
    48. Uintptr
    49. Float32
    50. Float64
    51. Complex64
    52. Complex128
    53. Array
    54. Chan
    55. Func
    56. Interface
    57. Map
    58. Pointer
    59. Slice
    60. String
    61. Struct
    62. UnsafePointer
    63. )
    64. `)
    65. }

    运行效果:


    GOROOT=D:\program_file_worker\go1.20 #gosetup
    GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
    D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_reflect.exe org.jd.data/org.jd.data/reflect #gosetup
    C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_reflect.exe
    ========================-获取变量result的类型===============
    变量的静态类型为:interface{}在变量运行状态下获取result变量的类型为:
      string
    ==========================动态获取变量result的值=============

    变量的值为: string

            下面来看下kind的源代码:
            type Kind uint

    const (
            Invalid Kind = iota
            Bool
            Int
            Int8
            Int16
            Int32
            Int64
            Uint
            Uint8
            Uint16
            Uint32
            Uint64
            Float32
            Float64
            Complex64
            Complex128
            Array
            Chan
            Func
            Interface
            Map
            Pointer
            Slice
            String
            Struct
            UnsafePointer
    )

    Process finished with the exit code 0
     

    二: go语言反射中Kind类常量认知


    提示: Go语言不支持解析string然后执行,Go语言的反射机制只能作用在“已经存在的对象”上
    
          Go语言中的反射的种类(Kind):
             type Kind uint
    
    const (
    
       Invalid Kind = iota  // 非法的类型
       Bool        // 布尔型
       Int         // 有符号整形
       Int8        // 有符号8位整形
       Int16       // 有符号16位整形
       Int32       // 有符号32位整形
       Int64       // 有符号64位整形
       Uint        // 无符号整形
       Uint8       // 无符号8位整形
       Uint16      // 无符号16位整形
       Uint32      // 无符号32位整形
       Uint64      // 无符号64位整形
       Float32     // 单精度浮点数
       Float64      // 双精度浮点数
       Complex64    // 64复数类型
       Complex128   // 128复数类型
       Array        // 数值
       Chan         // 通道
       Func         // 函数
       Interface    // 接口
       Map          // 映射
       Pointer      // 指针
       Slice        // 切片
       String       // 字符串
       Struct       //  结构体
       UnsafePointer // 底层指针
    
    )
    
    其中Map,Slice,Chan属于引用类型,使用起来类似于指针,但是在种类常量中仍然属于独立的种类,
    
       不属于Ptr。type A struct{}定义的结构体属于Struct种类,*A属于Ptr;通常在使用反射来获取变量的类型时,就是用reflect.Kind()来判断所属系统类型

    1. package main
    2. import (
    3. "fmt"
    4. "reflect"
    5. )
    6. /*
    7. 提示: Go语言不支持解析string然后执行,Go语言的反射机制只能作用在“已经存在的对象”上
    8. Go语言中的反射的种类(Kind):
    9. type Kind uint
    10. const (
    11. Invalid Kind = iota // 非法的类型
    12. Bool // 布尔型
    13. Int // 有符号整形
    14. Int8 // 有符号8位整形
    15. Int16 // 有符号16位整形
    16. Int32 // 有符号32位整形
    17. Int64 // 有符号64位整形
    18. Uint // 无符号整形
    19. Uint8 // 无符号8位整形
    20. Uint16 // 无符号16位整形
    21. Uint32 // 无符号32位整形
    22. Uint64 // 无符号64位整形
    23. Float32 // 单精度浮点数
    24. Float64 // 双精度浮点数
    25. Complex64 // 64复数类型
    26. Complex128 // 128复数类型
    27. Array // 数值
    28. Chan // 通道
    29. Func // 函数
    30. Interface // 接口
    31. Map // 映射
    32. Pointer // 指针
    33. Slice // 切片
    34. String // 字符串
    35. Struct // 结构体
    36. UnsafePointer // 底层指针
    37. )
    38. 其中Map,Slice,Chan属于引用类型,使用起来类似于指针,但是在种类常量中仍然属于独立的种类,
    39. 不属于Ptr。type A struct{}定义的结构体属于Struct种类,*A属于Ptr;通常在使用反射来获取变量的类型时,就是用reflect.Kind()来判断所属系统类型
    40. */
    41. func main() {
    42. var a int
    43. typeOfA := reflect.TypeOf(a)
    44. if typeOfA.Kind() == reflect.Int {
    45. fmt.Printf("变量a的类型kind是 %s ,kind.type: %s", typeOfA.Name(), typeOfA.Kind())
    46. } else {
    47. fmt.Printf("变量a的类型kind是 %s", typeOfA.Kind())
    48. }
    49. }

    运行效果:


    GOROOT=D:\program_file_worker\go1.20 #gosetup
    GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
    D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_OOPReflectToGrammarBaseUse_go.exe D:\program_file\go_workspace\org.jd.data\reflect\OOPReflectToGrammarBaseUse.go #gosetup
    C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_OOPReflectToGrammarBaseUse_go.exe
    变量a的类型kind是 int ,kind.type: int
    Process finished with the exit code 0


     

    三: go语言反射获取类型信息


    1. package main
    2. import (
    3. "fmt"
    4. "reflect"
    5. )
    6. /*
    7. 通过反射获取类型信息
    8. */
    9. func main() {
    10. println("=============1====================")
    11. var num Number = 10
    12. typeOfNum := reflect.TypeOf(num)
    13. fmt.Printf("typeOfNum")
    14. checkType(typeOfNum)
    15. println("=============2====================")
    16. var person Person
    17. typeOfPerson := reflect.TypeOf(person)
    18. fmt.Printf("typeOfPerson")
    19. checkType(typeOfPerson)
    20. println("=============3====================")
    21. typeOfPersonPtr := reflect.TypeOf(&person)
    22. fmt.Printf("typeOfPersonPtr")
    23. checkType(typeOfPersonPtr)
    24. }
    25. type Number int
    26. type Person struct {
    27. }
    28. // 定义一个检查数据类型的函数
    29. func checkType(t reflect.Type) {
    30. if t.Kind() == reflect.Ptr {
    31. fmt.Printf("变量的类型名称%v ,指向的变量的值为: ", t.Kind())
    32. t = t.Elem()
    33. }
    34. fmt.Printf("变量的类型名称 ==> %v ,类型种类 ==> %v \n", t.Name(), t.Kind())
    35. }

     运行效果:


    GOROOT=D:\program_file_worker\go1.20 #gosetup
    GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
    D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_reflect__1_.exe D:\program_file\go_workspace\org.jd.data\reflect\OOPReflectToGrammarBaseUseFindTypeInfo.go #gosetup
    C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_reflect__1_.exe
    =============1====================

    Process finished with the exit code 0

    typeOfNum变量的类型名称 ==> Number ,类型种类 ==> int
    =============2====================
    typeOfPerson变量的类型名称 ==> Person ,类型种类 ==> struct
    =============3====================
    typeOfPersonPtr变量的类型名称ptr ,指向的变量的值为: 变量的类型名称 ==> Person ,类型种类 ==> struct


     

    四: go语言反射获取类型的值信息


    1. package main
    2. import (
    3. "fmt"
    4. "reflect"
    5. )
    6. /*
    7. 通过反射获取类型的值信息
    8. */
    9. func main() {
    10. println("================1=====================")
    11. var num int = 10
    12. valueOfNum := reflect.ValueOf(num)
    13. fmt.Println("valueOfNum")
    14. checkValue(valueOfNum)
    15. println("================2=====================")
    16. valueOfNumPtr := reflect.ValueOf(&num)
    17. fmt.Println("valueOfNumPtr")
    18. checkValue(valueOfNumPtr)
    19. }
    20. // 定义一个获取数据类型的值的函数
    21. func checkValue(v reflect.Value) {
    22. if v.Kind() == reflect.Ptr {
    23. v = v.Elem()
    24. }
    25. if v.Kind() == reflect.Int {
    26. // 方法一
    27. var v1 = int(v.Int())
    28. // 方法二
    29. var v2 int = v.Interface().(int)
    30. fmt.Println(v1, v2)
    31. }
    32. }

    运行效果:
     


    GOROOT=D:\program_file_worker\go1.20 #gosetup
    GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
    D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_OOPReflectToGrammarBaseUseFindValueInfo_go.exe D:\program_file\go_workspace\org.jd.data\reflect\OOPReflectToGrammarBaseUseFindValueInfo.go #gosetup
    C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_OOPReflectToGrammarBaseUseFindValueInfo_go.exe
    ================1=====================
    valueOfNum
    10 10
    ================2=====================
    valueOfNumPtr
    10 10

    Process finished with the exit code 0

    五: go使用反射动态调用函数


    go语言反射动态调用函数
        使用反射调用函数需要用到reflect.ValueOf()方法,传入想要反射的函数名,
        获取到reflect.Value对象,在通过reflect.Value对象的Call方法调用该函数,Call方法的声明如下
            func (v Value) Call(in []Value) []Value
         Call方法使用输入的参数in调用v持有的函数。例如,如果len(in)==3,v.Call(in)代表调用v(in[0],in[1],
         in[2]) (其中Value值表示其持有的值)。如果v的Kind不是Func会引发panic。它返回函数所有输出结果的Value
         封装的切片。和Go代码一样,每一个输入参数的持有值都必须可以直接赋值给函数对应输入参数的类型。如果持有值是可
         变参数函数,Call方法会自行创建一个代表可变参数的切片,将对应可变参数的值都拷贝到里面;

    1. package main
    2. import (
    3. "fmt"
    4. "reflect"
    5. )
    6. /*
    7. go语言反射动态调用函数
    8. 使用反射调用函数需要用到reflect.ValueOf()方法,传入想要反射的函数名,
    9. 获取到reflect.Value对象,在通过reflect.Value对象的Call方法调用该函数,Call方法的声明如下
    10. func (v Value) Call(in []Value) []Value
    11. Call方法使用输入的参数in调用v持有的函数。例如,如果len(in)==3,v.Call(in)代表调用v(in[0],in[1],
    12. in[2]) (其中Value值表示其持有的值)。如果v的Kind不是Func会引发panic。它返回函数所有输出结果的Value
    13. 封装的切片。和Go代码一样,每一个输入参数的持有值都必须可以直接赋值给函数对应输入参数的类型。如果持有值是可
    14. 变参数函数,Call方法会自行创建一个代表可变参数的切片,将对应可变参数的值都拷贝到里面;
    15. */
    16. func main() {
    17. // 反射调用函数需使用ValueOf
    18. valueOfFunc := reflect.ValueOf(Equal)
    19. // 构造函数参数
    20. args := []reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)}
    21. // 通过反射调用函数计算
    22. result := valueOfFunc.Call(args)
    23. fmt.Println("函数运行的结果: ", result[0].Bool())
    24. }
    25. func Equal(a, b int) bool {
    26. if a == b {
    27. return true
    28. }
    29. return false
    30. }

    运行效果:


    GOROOT=D:\program_file_worker\go1.20 #gosetup
    GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
    D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_reflect__2_.exe D:\program_file\go_workspace\org.jd.data\reflect\OOPReflectToGrammarBaseUseCallFunc.go #gosetup
    C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_reflect__2_.exe
    函数运行的结果:  false

    Process finished with the exit code 0
     

    六: 结构体的反射操作


    对结构体的操作:
    
       反射不仅可以获取普通类型变量的值,还可以获取结构体的成员的类型,成员变量的值以及调用结构体的方法
       获取结构体成员类型
          结构体通过reflect.Type()获取反射类型的变量后,可以调用reflect.Type对象的NumField()方法
        获取结构体成员的变量,调用Field()则可以根据索引返回对应结构体字段的详细信息,具体如下:
        // A StructField describes a single field in a struct.
    
       type StructField struct {
          Name string         // 字段名
          PkgPath string      // 字段路径
          Type      Type      // 字段反射类型对象
          Tag       StructTag // 字段结构体标签
          Offset    uintptr   // 字段在结构体中的偏移
          Index     []int     // 字段的索引值
          Anonymous bool      // 是否是匿名字段

    实例一:反射获取结构体的成员类型

    1. package main
    2. import (
    3. "fmt"
    4. "reflect"
    5. )
    6. /*
    7. 对结构体的操作:
    8. 反射不仅可以获取普通类型变量的值,还可以获取结构体的成员的类型,成员变量的值以及调用结构体的方法
    9. 获取结构体成员类型
    10. 结构体通过reflect.Type()获取反射类型的变量后,可以调用reflect.Type对象的NumField()方法
    11. 获取结构体成员的变量,调用Field()则可以根据索引返回对应结构体字段的详细信息,具体如下:
    12. // A StructField describes a single field in a struct.
    13. type StructField struct {
    14. Name string // 字段名
    15. PkgPath string // 字段路径
    16. Type Type // 字段反射类型对象
    17. Tag StructTag // 字段结构体标签
    18. Offset uintptr // 字段在结构体中的偏移
    19. Index []int // 字段的索引值
    20. Anonymous bool // 是否是匿名字段
    21. */
    22. func main() {
    23. println("===============1============================\n")
    24. person := PersonStruct{"老表", 20, "备注"}
    25. typeOfPersonStruct := reflect.TypeOf(person)
    26. // 遍历所有结构体成员获取字段信息
    27. fmt.Println("遍历结构体")
    28. for i := 0; i < typeOfPersonStruct.NumField(); i++ {
    29. field := typeOfPersonStruct.Field(i)
    30. fmt.Printf("字段名: %v 字段标签: %v 是否是匿名字段: %v \n",
    31. field.Name, field.Tag, field.Anonymous)
    32. }
    33. println("===============2============================\n")
    34. println()
    35. // 通过字段名获取字段信息
    36. if field, ok := typeOfPersonStruct.FieldByName("Age"); ok {
    37. fmt.Println("通过字段名")
    38. fmt.Printf("字段名: %v, 字段标签中json: %v \n", field.Name, field.Tag.Get("json"))
    39. }
    40. println()
    41. println("===============3============================\n")
    42. // 通过下标获取字段信息
    43. field := typeOfPersonStruct.FieldByIndex([]int{1})
    44. fmt.Println("通过下标")
    45. fmt.Printf("字段名: %v 字段标签: %v 是否是匿名字段: %v \n", field.Name, field.Tag, field.Anonymous)
    46. }
    47. type PersonStruct struct {
    48. Name string
    49. Age int `json:"age"`
    50. string // 匿名字段,只有类型,没有字段名称
    51. }

    运行效果:


    GOROOT=D:\program_file_worker\go1.20 #gosetup
    GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
    D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_OOPReflectToGrammarBaseUseStructInfo_go.exe D:\program_file\go_workspace\org.jd.data\reflect\OOPReflectToGrammarBaseUseStructInfo.go #gosetup
    C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_OOPReflectToGrammarBaseUseStructInfo_go.exe
    ===============1============================

    遍历结构体
    字段名: Name   字段标签:   是否是匿名字段: false
    字段名: Age   字段标签:  json:"age" 是否是匿名字段: false
    字段名: string   字段标签:   是否是匿名字段: true
    ===============2============================


    通过字段名
    字段名: Age, 字段标签中json: age

    ===============3============================

    通过下标
    字段名: Age   字段标签:  json:"age" 是否是匿名字段: false

    Process finished with the exit code 0


    实例二:反射获取结构体的成员变量值及调用结构体的方法


    1. package main
    2. import (
    3. "fmt"
    4. "reflect"
    5. )
    6. /*
    7. 反射获取结构体成员字段的值
    8. */
    9. func main() {
    10. println("===================1================================")
    11. person := PersonValue{Name: "老杨", Age: 27, Address: "北京市海淀区马连洼街道25号院", College: "北京大学"}
    12. fmt.Printf("打印匿名字段[默认类型初始值]: %d \n", person.int)
    13. valueOfPersonValue := reflect.ValueOf(person)
    14. fmt.Printf("person的成员字段数量: %d \n", valueOfPersonValue.NumField())
    15. // 通过下标访问获取字段值
    16. fmt.Println("Field")
    17. field := valueOfPersonValue.Field(1)
    18. fmt.Println("字段值: ", field.Int())
    19. println("===================2================================")
    20. // 通过字段名称获取字段的值
    21. field = valueOfPersonValue.FieldByName("Age")
    22. fmt.Println("FieldByName")
    23. fmt.Printf("字段值: %v \n", field.Interface())
    24. println("===================3================================")
    25. // 通过下标获取字段的值
    26. field = valueOfPersonValue.FieldByIndex([]int{0})
    27. fmt.Println("FieldByIndex")
    28. fmt.Printf("字段值: %v \n", field.Interface())
    29. println("===================4================================")
    30. methodFindName := valueOfPersonValue.MethodByName("GetName")
    31. // 执行结构体的方法
    32. methodFindName.Call([]reflect.Value{}) // 传递一个Value类型的空数据作为函数的参数
    33. }
    34. // PersonValue 当我们定义结构体的时候,字段可以只有类型, 而没有字段名,这样的字段称为匿名字段(Anonymous Field)
    35. type PersonValue struct {
    36. Name string
    37. Age int `json:"age"`
    38. Address string `json:"address"`
    39. College string
    40. int // 匿名字段
    41. }
    42. // GetName 结构体的方法
    43. func (p PersonValue) GetName() {
    44. fmt.Println(p.Name)
    45. }

    运行效果:


    GOROOT=D:\program_file_worker\go1.20 #gosetup
    GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
    D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_OOPReflectToGrammarBaseUseStructValueInfo_go.exe D:\program_file\go_workspace\org.jd.data\reflect\OOPReflectToGrammarBaseUseStructValueInfo.go #gosetup
    C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_OOPReflectToGrammarBaseUseStructValueInfo_go.exe
    ===================1================================
    打印匿名字段[默认类型初始值]: 0
    person的成员字段数量: 5
    Field
    字段值:  27
    ===================2================================
    FieldByName
    字段值: 27
    ===================3================================
    FieldByIndex
    字段值: 老杨
    ===================4================================
    老杨

    Process finished with the exit code 0
     

    七: go语言反射三大定律认知


    反射三大定律认知升维:
    定律一:反射可以将接口类型的数据变量转换为反射类型的变量
       (1)在使用反射的时候,牢记反射的三大定律会让你对反射有更加清晰的认识
        (2)反射第一定律的体现函数
           2.1 来看下reflect.TypeOf()与reflect.ValueOf()函数的签名:
          func TypeOf(i interface{}) Type {
          }
            func ValueOf(i interface{}) Value {
          }
           2.2 这两个函数的方法类型是reflect.Type和reflect.Value;而这个数据类型称为反射类型
         (3)这两个函数如此都是接口类型变量入参,返回类型为反射类型
    定律二:反射可以将反射类型变量转换为接口类型变量
         这里主要使用reflect.Value对象的Interface()方法
    定律三:想要使用反射来修改变量的值,其值必须是可写(CanSet)。
       这个值必须满足两个条件:
          一是变量可以被寻址(CanAddr)
          二是变量是可以导出的(结构体字段的首字母需大写)

    1. package main
    2. import (
    3. "fmt"
    4. "reflect"
    5. )
    6. /*
    7. 反射三大定律认知升维:
    8. 定律一:反射可以将接口类型的数据变量转换为反射类型的变量
    9. (1)在使用反射的时候,牢记反射的三大定律会让你对反射有更加清晰的认识
    10. (2)反射第一定律的体现函数
    11. 2.1 来看下reflect.TypeOf()与reflect.ValueOf()函数的签名:
    12. func TypeOf(i interface{}) Type {
    13. }
    14. func ValueOf(i interface{}) Value {
    15. }
    16. 2.2 这两个函数的方法类型是reflect.Type和reflect.Value;而这个数据类型称为反射类型
    17. (3)这两个函数如此都是接口类型变量入参,返回类型为反射类型
    18. 定律二:反射可以将反射类型变量转换为接口类型变量
    19. 这里主要使用reflect.Value对象的Interface()方法
    20. 定律三:想要使用反射来修改变量的值,其值必须是可写(CanSet)。
    21. 这个值必须满足两个条件:
    22. 一是变量可以被寻址(CanAddr)
    23. 二是变量是可以导出的(结构体字段的首字母需大写)
    24. */
    25. func main() {
    26. println("========================反射第一定律=============================================\n")
    27. var a int = 5
    28. fmt.Printf("type:%T \n", reflect.TypeOf(a))
    29. fmt.Printf("value:%T \n", reflect.ValueOf(a))
    30. println("========================反射第二定律=============================================\n")
    31. var b int = 20
    32. valueOfb := reflect.ValueOf(b)
    33. fmt.Printf("字段b的值: %d", valueOfb.Interface())
    34. println("========================反射第三定律=============================================\n")
    35. animal := Animal{"旺财", 20, "四足爬行类"}
    36. valueOfAnimal := reflect.ValueOf(&animal)
    37. typeOfAnimal := reflect.TypeOf(&animal)
    38. for i := 0; i < valueOfAnimal.Elem().NumField(); i++ {
    39. fieldValue := valueOfAnimal.Elem().Field(i)
    40. fieldType := typeOfAnimal.Elem().Field(i)
    41. fmt.Printf("类型名: %v 可以寻址: %v 可以设置: %v \n",
    42. fieldType.Name, fieldValue.CanAddr(), valueOfAnimal.CanSet())
    43. }
    44. println()
    45. fmt.Println("修改前: ", animal)
    46. // 必须满足可寻址和可导出才能修改变量值
    47. valueOfAnimal.Elem().Field(0).SetString("小咪咪")
    48. fmt.Println("修改后: ", animal)
    49. }
    50. type Animal struct {
    51. Name string
    52. age int `json:"age"`
    53. string
    54. }


    运行效果:


    GOROOT=D:\program_file_worker\go1.20 #gosetup
    GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
    D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_OOPReflectToGrammarBaseThreeLaws_go.exe D:\program_file\go_workspace\org.jd.data\reflect\OOPReflectToGrammarBaseThreeLaws.go #gosetup
    C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_OOPReflectToGrammarBaseThreeLaws_go.exe
    ========================反射第一定律=============================================


    type:*reflect.rtype
    value:reflect.Value
    ========================反射第二定律=============================================


    字段b的值: 20========================反射第三定律=============================================


    类型名: Name  可以寻址: true  可以设置: false
    类型名: age  可以寻址: true  可以设置: false
    类型名: string  可以寻址: true  可以设置: false

    修改前:  {旺财 20 四足爬行类}
    修改后:  {小咪咪 20 四足爬行类}

    Process finished with the exit code 0

  • 相关阅读:
    操作指南|JumpServer与Keycloak集成对接
    10、乐趣国学—践行《弟子规》的“谨”懂得从容之道(下篇)
    综合能力 ---- 2. 法律法规
    【C语言】深入理解KMP算法及C语言实现
    表单标签。。
    前端 | Ajax&Axios模块
    C语言笔记(进行中)!!!
    zabbix监控华为2288hv5服务器
    图书管理系统【java】
    C. String Equality(思维)
  • 原文地址:https://blog.csdn.net/u014635374/article/details/133989486