火花机 东莞网站建设,产品软文范例500字,wordpress的ico,重庆品牌策划公司排名1.reflect包作用
reflect包定义了“反射”相关能力#xff0c;“反射”在计算机学中是指计算机程序在运行时#xff08;runtime#xff09;可以访问、检测和修改它本身状态或行为的一种能力。基于反射特性可以通用化地解决一些需要频繁修改代码及硬编码问题#xff0c;但是…1.reflect包作用
reflect包定义了“反射”相关能力“反射”在计算机学中是指计算机程序在运行时runtime可以访问、检测和修改它本身状态或行为的一种能力。基于反射特性可以通用化地解决一些需要频繁修改代码及硬编码问题但是执行效率会被降低。
2.核心API
参考官方文档https://pkg.go.dev/reflect#pkg-functions
3.使用案例
3.1.类型判断
用途判断接口属于某种类型后进行特定处理主要使用TypeOf、Kind
type User struct {Name stringAge int
}type IUserService interface {GetUser(userID int64) User
}func reflectType() {var (intType intstringType *stringmapType map[string]interface{}structType *UserinterfaceType IUserService)var types []interface{}types append(types, intType)types append(types, stringType)types append(types, mapType)types append(types, structType)types append(types, interfaceType)// 类型判断for i, v : range types {rtyp : reflect.TypeOf(v)if rtyp nil {fmt.Printf((%v)类型获取Type为nil跳过\n, i)continue}rkind : rtyp.Kind()// 如果为指针类型还原出真实类型if rtyp.Kind() reflect.Ptr {fmt.Printf((%v)指针类型: %v\n, i, rkind.String())rtyp rtyp.Elem()}rkind rtyp.Kind()fmt.Printf((%v)类型%v\n, i, rkind.String())}
}输出
(0)类型int
(1)指针类型: ptr
(1)类型string
(2)类型map
(3)指针类型: ptr
(3)类型struct
(4)类型获取Type为nil跳过3.2.变量值获取
用于获取类型的值主要使用ValueOf、Kind
func reflectValue() {var (intType int 10stringType string hello worldmapType map[string]interface{} nil)var types []interface{}types append(types, intType)types append(types, stringType)types append(types, mapType)// 类型判断for i, v : range types {rval : reflect.ValueOf(v)if rval.Kind() reflect.Ptr {rval rval.Elem()}fmt.Printf((%v)的值%v\n, i, rval.Interface())}
}输出
(0)的值10
(1)的值hello world
(2)的值map[]3.3.遍历结构体的字段及值
用途遍历未知类型结构体的字段及值避免硬编码结构体处理主要使用TypeOf、ValueOf、NumField
func rangeStruct() {u : User{Name: arong,Age: 23,Favors: []Favor{{Name: 篮球,ID: 1,},{Name: 唱跳,ID: 2,},{Name: RAP,ID: 3,},},}rval : reflect.ValueOf(u)if rval.Kind() reflect.Ptr {rval rval.Elem()}for i : 0; i rval.NumField(); i {name : rval.Type().Field(i).Nameval : rval.Field(i).Interface()fmt.Printf(字段%v值为%v\n, name, val)}
}输出
字段Name值为arong
字段Age值为23
字段Favors值为[{篮球 1} {唱跳 2} {RAP 3}]3.4.结构体字段赋值
用途对未知结构体的特定字段进行赋值主要使用ValueOf、FieldByName、CanSet、Set
func reflectSetValue() {u : User{Name: arong,Age: 23,}fmt.Printf(原始字段值:%#v\n, u)// 一定要取指针不然无法赋值rval : reflect.ValueOf(u).Elem()rvalNameField : rval.FieldByName(Name)// 字段是否可写入if rvalNameField.CanSet() {rvalNameField.Set(reflect.ValueOf(pbrong))}fmt.Printf(改变已知字段值:%#v\n, u)
}
3.5.函数及方法调用
- 用途使用反射动态调用指定函数及方法
- 主要使用
type User struct {Name stringAge intFavors []Favor
}type IUserService interface {GetUser(userID int64) User
}type UserService struct {
}func (u *UserService) GetUser(userID int64) User {user : User{Name: defaultTestUser,Age: -1,Favors: []Favor{},}fmt.Printf(GetUser exec: result %#v\n, user)return user
}func TestFunc(names string) {fmt.Printf(TestFunc exec: result %v\n, names)
}func reflectSetValue() {u : User{Name: arong,Age: 23,}fmt.Printf(原始字段值:%#v\n, u)// 一定要取指针不然无法赋值rval : reflect.ValueOf(u).Elem()rvalNameField : rval.FieldByName(Name)// 字段是否可写入if rvalNameField.CanSet() {rvalNameField.Set(reflect.ValueOf(pbrong))}fmt.Printf(改变已知字段值:%#v\n, u)
}输出
TestFunc exec: result pbrong
GetUser exec: result main.User{Name:defaultTestUser, Age:-1, Favors:[]main.Favor{}}
GetUser resp: main.User{Name:defaultTestUser, Age:-1, Favors:[]main.Favor{}}4.避免滥用反射
反射使用不当可能会影响程序的性能和可读性。因此在 Go 中我们通常建议尽可能地避免滥用反射。 主要的原因是反射的本质是一种运行时类型转换会导致一定的开销。因为它需要动态地获取类型信息进行类型检查以及在运行时动态地分配内存等。这些操作都比静态类型转换需要更多的计算资源和时间。 另外由于反射的使用不够直观和简洁可能会降低代码的可读性和可维护性。特别是当开发人员不了解反射的工作原理时容易出现一些难以调试和排查的问题。 因此通常情况下我们应该尽可能地避免滥用反射。只有在必要的场景下才使用反射例如需要在运行时动态地创建对象、调用函数、解析数据等。在其他场景下我们应该尽可能使用 Go 的静态类型系统和语言特性使得代码更加简洁、高效和可读。