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

编程入门 行业动态 更新时间:2024-10-26 20:34:29

Go语言入门<a href=https://www.elefans.com/category/jswz/34/1756517.html style=心法(十三): 反射认知升维"/>

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有着很大的区别


反射实例一:


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

运行效果:


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 uintconst (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()来判断所属系统类型

package mainimport ("fmt""reflect"
)/*
提示: Go语言不支持解析string然后执行,Go语言的反射机制只能作用在“已经存在的对象”上Go语言中的反射的种类(Kind):type Kind uintconst (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()来判断所属系统类型
*/
func main() {var a inttypeOfA := reflect.TypeOf(a)if typeOfA.Kind() == reflect.Int {fmt.Printf("变量a的类型kind是 %s ,kind.type: %s", typeOfA.Name(), typeOfA.Kind())} else {fmt.Printf("变量a的类型kind是 %s", typeOfA.Kind())}}

运行效果:


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语言反射获取类型信息


package mainimport ("fmt""reflect"
)/*
通过反射获取类型信息
*/
func main() {println("=============1====================")var num Number = 10typeOfNum := reflect.TypeOf(num)fmt.Printf("typeOfNum")checkType(typeOfNum)println("=============2====================")var person PersontypeOfPerson := reflect.TypeOf(person)fmt.Printf("typeOfPerson")checkType(typeOfPerson)println("=============3====================")typeOfPersonPtr := reflect.TypeOf(&person)fmt.Printf("typeOfPersonPtr")checkType(typeOfPersonPtr)
}type Number inttype Person struct {
}// 定义一个检查数据类型的函数
func checkType(t reflect.Type) {if t.Kind() == reflect.Ptr {fmt.Printf("变量的类型名称%v ,指向的变量的值为: ", t.Kind())t = t.Elem()}fmt.Printf("变量的类型名称 ==> %v ,类型种类 ==> %v  \n", t.Name(), t.Kind())
}

 运行效果:


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语言反射获取类型的值信息


package mainimport ("fmt""reflect"
)/*
通过反射获取类型的值信息
*/
func main() {println("================1=====================")var num int = 10valueOfNum := reflect.ValueOf(num)fmt.Println("valueOfNum")checkValue(valueOfNum)println("================2=====================")valueOfNumPtr := reflect.ValueOf(&num)fmt.Println("valueOfNumPtr")checkValue(valueOfNumPtr)}// 定义一个获取数据类型的值的函数
func checkValue(v reflect.Value) {if v.Kind() == reflect.Ptr {v = v.Elem()}if v.Kind() == reflect.Int {// 方法一var v1 = int(v.Int())// 方法二var v2 int = v.Interface().(int)fmt.Println(v1, v2)}}

运行效果:
 


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) []ValueCall方法使用输入的参数in调用v持有的函数。例如,如果len(in)==3,v.Call(in)代表调用v(in[0],in[1],in[2]) (其中Value值表示其持有的值)。如果v的Kind不是Func会引发panic。它返回函数所有输出结果的Value封装的切片。和Go代码一样,每一个输入参数的持有值都必须可以直接赋值给函数对应输入参数的类型。如果持有值是可变参数函数,Call方法会自行创建一个代表可变参数的切片,将对应可变参数的值都拷贝到里面;

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

运行效果:


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      // 是否是匿名字段

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

package mainimport ("fmt""reflect"
)/*
对结构体的操作:反射不仅可以获取普通类型变量的值,还可以获取结构体的成员的类型,成员变量的值以及调用结构体的方法获取结构体成员类型结构体通过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      // 是否是匿名字段
*/
func main() {println("===============1============================\n")person := PersonStruct{"老表", 20, "备注"}typeOfPersonStruct := reflect.TypeOf(person)// 遍历所有结构体成员获取字段信息fmt.Println("遍历结构体")for i := 0; i < typeOfPersonStruct.NumField(); i++ {field := typeOfPersonStruct.Field(i)fmt.Printf("字段名: %v   字段标签:  %v 是否是匿名字段: %v  \n",field.Name, field.Tag, field.Anonymous)}println("===============2============================\n")println()// 通过字段名获取字段信息if field, ok := typeOfPersonStruct.FieldByName("Age"); ok {fmt.Println("通过字段名")fmt.Printf("字段名: %v, 字段标签中json: %v  \n", field.Name, field.Tag.Get("json"))}println()println("===============3============================\n")// 通过下标获取字段信息field := typeOfPersonStruct.FieldByIndex([]int{1})fmt.Println("通过下标")fmt.Printf("字段名: %v   字段标签:  %v 是否是匿名字段: %v  \n", field.Name, field.Tag, field.Anonymous)
}type PersonStruct struct {Name   stringAge    int `json:"age"`string     // 匿名字段,只有类型,没有字段名称
}

运行效果:


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


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


package mainimport ("fmt""reflect"
)/*
反射获取结构体成员字段的值
*/
func main() {println("===================1================================")person := PersonValue{Name: "老杨", Age: 27, Address: "北京市海淀区马连洼街道25号院", College: "北京大学"}fmt.Printf("打印匿名字段[默认类型初始值]: %d \n", person.int)valueOfPersonValue := reflect.ValueOf(person)fmt.Printf("person的成员字段数量: %d \n", valueOfPersonValue.NumField())// 通过下标访问获取字段值fmt.Println("Field")field := valueOfPersonValue.Field(1)fmt.Println("字段值: ", field.Int())println("===================2================================")// 通过字段名称获取字段的值field = valueOfPersonValue.FieldByName("Age")fmt.Println("FieldByName")fmt.Printf("字段值: %v \n", field.Interface())println("===================3================================")// 通过下标获取字段的值field = valueOfPersonValue.FieldByIndex([]int{0})fmt.Println("FieldByIndex")fmt.Printf("字段值: %v \n", field.Interface())println("===================4================================")methodFindName := valueOfPersonValue.MethodByName("GetName")// 执行结构体的方法methodFindName.Call([]reflect.Value{}) // 传递一个Value类型的空数据作为函数的参数}// PersonValue 当我们定义结构体的时候,字段可以只有类型, 而没有字段名,这样的字段称为匿名字段(Anonymous Field)
type PersonValue struct {Name    stringAge     int    `json:"age"`Address string `json:"address"`College stringint     // 匿名字段
}// GetName 结构体的方法
func (p PersonValue) GetName() {fmt.Println(p.Name)
}

运行效果:


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)二是变量是可以导出的(结构体字段的首字母需大写)

package mainimport ("fmt""reflect"
)/*
反射三大定律认知升维:
定律一:反射可以将接口类型的数据变量转换为反射类型的变量(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)二是变量是可以导出的(结构体字段的首字母需大写)
*/
func main() {println("========================反射第一定律=============================================\n")var a int = 5fmt.Printf("type:%T  \n", reflect.TypeOf(a))fmt.Printf("value:%T  \n", reflect.ValueOf(a))println("========================反射第二定律=============================================\n")var b int = 20valueOfb := reflect.ValueOf(b)fmt.Printf("字段b的值: %d", valueOfb.Interface())println("========================反射第三定律=============================================\n")animal := Animal{"旺财", 20, "四足爬行类"}valueOfAnimal := reflect.ValueOf(&animal)typeOfAnimal := reflect.TypeOf(&animal)for i := 0; i < valueOfAnimal.Elem().NumField(); i++ {fieldValue := valueOfAnimal.Elem().Field(i)fieldType := typeOfAnimal.Elem().Field(i)fmt.Printf("类型名: %v  可以寻址: %v  可以设置: %v \n",fieldType.Name, fieldValue.CanAddr(), valueOfAnimal.CanSet())}println()fmt.Println("修改前: ", animal)// 必须满足可寻址和可导出才能修改变量值valueOfAnimal.Elem().Field(0).SetString("小咪咪")fmt.Println("修改后: ", animal)}type Animal struct {Name stringage  int `json:"age"`string
}


运行效果:


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

更多推荐

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

本文发布于:2023-12-03 20:57:27,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1657570.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:心法   反射   认知   入门   语言

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!