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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/119590.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Win安装protobuf和IDEA使用protobuf插件

一、Win安装protobuf 1、下载编译器 protobuf下载地址&#xff1a;https://github.com/protocolbuffers/protobuf/releases 选择自己需要的版本下载&#xff0c;这里下载的是 protoc-3.19.1-win64.zip&#xff0c;下载之后进行解压即可。 2、配置环境变量 path 系统变量中添加…

RT-Thread 7. RT-Thread Studio ENV修改MCU型号

1. 修改MCU型号 2.在ENV界面输入 scons -c scons --dist3. dist下为更新后完整源代码 4.导入RT-Thread Studio 发现GD32F330已经生效了。 5. 自己编写startup_gd32f3x0.S&#xff0c;准确性待验证 ;/* ; * Copyright (c) 2006-2021, RT-Thread Development Team ; * ; * SPD…

如何将Mysql数据库的表导出并导入到另外的架构

如何将Mysql数据库的表导出并导入到另外的架构 准备一、解决方法1.右键->导出->用mysqldump导出2.注意路径一般为&#xff1a;C:/Program Files/MySQL/MySQL Server 8.0/bin/mysqldump.exe和导出的sql文件位置3.右键->SQL脚本->运行SQL脚本4.找到SQL脚本并点击确定…

通过实例理解Go Web身份认证的几种方式

在2023年Q1 Go官方用户调查报告[1]中&#xff0c;API/RPC services、Websites/web services都位于使用Go开发的应用类别的头部(如下图)&#xff1a; 我个人使用Go开发已很多年&#xff0c;但一直从事底层基础设施、分布式中间件等方向&#xff0c;Web应用开发领域涉及较少&…

SD-WAN跨境网络专线|跨境访问无忧!让海外SaaS平台与视频会议更稳定轻松的解决方案

在现如今全球化的时代&#xff0c;企业都有布局全球或是有潜力的国家&#xff0c;在海外开分公司必不可少&#xff0c;那与海外合作伙伴进行沟通与合作已经成为企业的常态。但是&#xff0c;访问海外的SaaS平台和进行视频会议时&#xff0c;我们经常会遇到网络不稳定、速度慢的…

idea 中配置 maven

前文叙述&#xff1a; 配置 maven 一共要设置两个地方&#xff1a;1、为当前项目设置2、为新项目设置maven 的下载和安装可参考我之前写过的文章&#xff0c;具体的配置文章中也都有讲解。1、为当前项目进行 maven 配置 配置 VM Options: -DarchetypeCataloginternal2、为新项…

CleanMyMac X免费macOS清理系统管家

近些年伴随着苹果生态的蓬勃发展&#xff0c;越来越多的用户开始尝试接触Mac电脑。然而很多人上手Mac后会发现&#xff0c;它的使用逻辑与Windows存在很多不同&#xff0c;而且随着使用时间的增加&#xff0c;一些奇奇怪怪的文件也会占据有限的磁盘空间&#xff0c;进而影响使用…

心理咨询医院预约和挂号系统

源码下载地址 支持&#xff1a;远程部署/安装/调试、讲解、二次开发/修改/定制 系统分为&#xff1a;患者端、医生端、管理员端。 患者端 医生端 管理员端

JAVA基础(JAVA SE)学习笔记(九)异常处理

前言 1. 学习视频&#xff1a; 尚硅谷Java零基础全套视频教程(宋红康2023版&#xff0c;java入门自学必备)_哔哩哔哩_bilibili 2023最新Java学习路线 - 哔哩哔哩 第三阶段&#xff1a;Java高级应用 9.异常处理 10.多线程 11.常用类和基础API 12.集合框架 13.泛型 14…

虚拟机VMware Workstation Pro安装配置使用服务器系统ubuntu-22.04.3-live-server-amd64.iso

虚拟机里安装ubuntu-23.04-beta-desktop-amd64开启SSH(换源和备份)配置中文以及中文输入法等 ​一、获取Ubuntu服务器版 获取Ubuntu服务器版 二、配置虚拟机 选择Custom(advanced)&#xff1a; 选择Workstation 17.x: 选择“I will install the operating system later.”…

原型制作的软件 Experience Design mac( XD ) 中文版软件特色

​XD是一个直观、功能强大的UI/UX开发工具&#xff0c;旨在设计、原型、用户之间共享材料以及通过数字技术进行设计交互。Adobe XD提供了开发网站、应用程序、语音界面、游戏界面、电子邮件模板等所需的一切。xd mac软件特色 体验设计的未来。 使用 Adobe XD 中快速直观、即取即…

上市公司员工及工资数据(2000-2022年)

参照《经济研究》中毛其淋等&#xff08;2023&#xff09;的做法&#xff0c;团队对上市公司员工、工资数据测算。用上市公司&#xff49;在&#xff54;年的员工人数的对数衡量企业的就业水平&#xff0c;采用企业应付职工薪酬与员工人数的比值衡量企业工资水平 一、数据介绍 …

html内连框架

src:引用页面地址 name&#xff1a;框架标识名称 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <!--iframe src&#xff1a;地址 w-h&#xff…

点云处理【七】(点云配准)

点云处理 第一章 点云数据采集 1.点云配准 点云配准是将两个或多个点云数据集融合到一个统一的坐标系统中的过程。这通常是为了创建一个完整的模型或融合从不同视角采集的数据。 点云配准一般分为粗配准和精配准&#xff0c;粗配准指的是在两幅点云之间的变换完全未知的情况下…

宝塔Python3.7安装模块报错ModuleNotFoundError: No module named ‘Crypto‘解决办法

前言 今晚遇到一个问题&#xff0c;宝塔服务器上安装脚本的模块时&#xff0c;出现以下报错&#xff0c;这里找到了解决办法 Traceback (most recent call last):File "/www/wwwroot/unifysign/fuck_chaoxing/fuck_xxt.py", line 4, in <module>from Crypto.…

[SQL开发笔记]BETWEEN操作符:选取介于两个值之间的数据范围内的值

一、功能描述&#xff1a; BETWEEN操作符&#xff1a;选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。 二、BETWEEN操作符语法详解&#xff1a; BETWEEN操作符语法&#xff1a; SELECT column1, column2,…FROM table_nameWHERE column BETWEEN val…

基于aop 代理 Sentinel Nacos配置控制包装类实现原理

基于aop & 代理 & Sentinel & Nacos配置控制包装类实现原理 Hi&#xff0c;我是阿昌&#xff0c;今天记录下看sentinel源码结合业务实现的思路基于aop & 代理 & Sentinel & Nacos配置控制包装类实现原理&#xff1b;下面并不会手把手的记录方案的实现…

Redis | 数据结构(02)SDS

一、键值对数据库是怎么实现的&#xff1f; 在开始讲数据结构之前&#xff0c;先给介绍下 Redis 是怎样实现键值对&#xff08;key-value&#xff09;数据库的。 Redis 的键值对中的 key 就是字符串对象&#xff0c;而 value 可以是字符串对象&#xff0c;也可以是集合数据类型…

【算法练习Day29】柠檬水找零根据身高重建队列用最少数量的箭引爆气球

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 柠檬水找零根据身高重建队列…

Web进阶

身份认证 当我们在使用互联网时&#xff0c;经常会遇到一些需要身份验证或者保持用户状态的情况。为了实现这些功能&#xff0c;常用的方法有使用cookie、session和token。 Cookie&#xff08;HTTP Cookie&#xff09;&#xff1a; Cookie是服务器发送到用户浏览器并保存在用户…