fccjxxw.com
非常超级学习网 学习超级帮手
当前位置:首页 >> 互联网 >>

兄弟连区块链培训教程之反射简介


兄弟连区块链培训教程之反射简介 首先 Go 是谷歌 2009 发布的第二款编程语言。今天兄弟连 Go 语言+区块链培训老师给 大家介绍一下关于 Go 语言之反射简介, 很多人喜欢 Go 语言, 其实是因为 Go 语言有其独特 的语言属性在支撑着其在编程语言界的发展,下面我们一起来看一下吧。

反射概述
? ? ? ?

通常的程序逻辑是:编码时先写好剧本,运行时按照写好的剧本演 何时创建一个什么实例,给哪个属性赋什么值,然后调用它的哪个方法都毫厘不差 但能否在运行时动态地生成“剧本”呢? 根据具体的业务需要见机行事,动态地生成一个不知道具体类型会是什么的实例, 动态地访问一个无法提前预知的属性或方法 答案是可以的,这便引出了今天的主角——反射

?

应用场景举例:导出商品列表到 Excel
?

需求是:不管用户在界面上看到什么商品列表,当它捅一下导出按钮,就将该商品 的所有属性和值写出为文件; 本例的难点是:我们无法预知用户会选择导出什么类型的商品数据、它有哪些属性, 也就无法相应地去创建 Excel 数据表的列(读写 Excel 有相应的库,你也可以选择写 出为文本文件、写出到数据库表中等等) 因为商品的种类太多,如果用正射去做,那么有多少商品类型我们就要写多少个 s witch 或 if 分支,然后在每一个分支里根据当前分支的具体商品类型去构造相应的 Exc el 数据列,这显然是蹩脚并且很难维护和扩展的 而通过反射来做就易如反掌了,管你来的是什么商品实例,立即动态解析得到其类 别、所有属性名值,然后根据属性名去创建 Excel 的列,根据属性值去做数据的填充 和写入

?

?

?

定义结构体
type Human struct { Name string "姓名" Age } func (h *Human) GetName() string {
1/9

int

"年龄"

fmt.Println("GetName called",h.Name) return h.Name } func (h *Human) SetName(name string) { fmt.Println("SetName called:", name) h.Name = name } func (h *Human) Eat(food string, grams int) (power int) { fmt.Println("Eat called:", food, grams) return 5 * grams }

反射功能一览
func main() {

//创建对象(在实际开发中可以是任意未知类型) h := Human{"bill", 60}

//获取任意对象的类型和值 getObjTypeValue(h)

2/9

//获得任意对象的所有属性 getObjFields(h)

//获取任意对象的所有方法 getObjMethods(&h)

//修改对象任意属性的值 modifyFieldValue(&h)

//动态调用对象的任意方法 callMethods(&h) fmt.Println("after:h=", h) }

获取任意对象的类型和值
func getObjTypeValue(obj interface{}) { oType := reflect.TypeOf(obj) oKind := oType.Kind() fmt.Println(oType, oKind)

oValue := reflect.ValueOf(obj)
3/9

fmt.Println(oValue)}

获得任意对象的所有属性
func getObjFields(obj interface{}) { oType := reflect.TypeOf(obj) oValue := reflect.ValueOf(obj)

fieldsCount := oType.NumField() for i := 0; i < fieldsCount; i++ {

//从对象值中获取第 i 个属性的值,进而值的“正射”形式 fValue := oValue.Field(i).Interface() structField := oType.Field(i) fmt.Println(structField.Name, structField.Type, structField.Tag, fValue) } }

获取任意对象的所有方法
func getObjMethods(obj interface{}) { oType := reflect.TypeOf(obj) fmt.Println(oType.NumMethod())

4/9

for i := 0; i < oType.NumMethod(); i++ { method := oType.Method(i) fmt.Println(method.Name, method.Type) } }

修改对象任意属性的值
func modifyFieldValue(objPtr interface{}) { //得到【指针的 Value】 oPtrValue := reflect.ValueOf(objPtr) //得到【指针所指向的值(结构体)的 Value】 oValue := oPtrValue.Elem() fmt.Println(oValue)

//遍历所有属性的值 for i := 0; i < oValue.NumField(); i++ {

//根据序号拿到【属性的 Value】 fValue := oValue.Field(i) //拿到属性值的原生类型 fKind := fValue.Kind()
5/9

//fmt.Println(fKind)

//根据不同的原生类型设置为不同的值 switch fKind { case reflect.String: fValue.SetString("张全蛋") case reflect.Int: fValue.SetInt(99) case reflect.Bool: fValue.SetBool(false) default: fmt.Println("设置为其他值...") } }

}

动态调用对象的任意方法
func callMethods(objPtr interface{}) {

//要通过对象的 oType 拿取方法的参数列表(oType.In(i))
6/9

oType := reflect.TypeOf(objPtr) //要通过对象的 oValue 拿取方法的具体实现(methodValue) oValue := reflect.ValueOf(objPtr)

//根据方法的数量进行遍历 for i := 0; i < oType.NumMethod(); i++ {

//预定义要传值的参数切片[]Value args := make([]reflect.Value, 0)

//从对象的 oType 拿到当前的方法的 methodType methodType := oType.Method(i).Type

//根据参数个数进行遍历 //为每个参数乱怼一个同种类型反射值,丢入参数列表 //内层循环走完时,当前方法的参数列表就形成了 for j:=0;j<methodType.NumIn();j++{

//从方法的 methodType 获取当前参数 artType artType := methodType.In(j)
7/9

//再获取参数类型 artType 的原生类型 argKind := artType.Kind()

//根据不同的参数原生类型乱怼相同类型的值 switch argKind {

case reflect.String: //获取字符串"一坨翔"的反射值 Value,丢入参数列表 args = append(args,reflect.ValueOf("一坨翔"))

case reflect.Int: args = append(args,reflect.ValueOf(100)) case reflect.Bool: args = append(args,reflect.ValueOf(false)) } }

//从对象值 oValue 中获取当前方法值 methodValue methodValue := oValue.Method(i)

8/9

//使用参数列表+方法值,反射调用当前方法 methodValue.Call(args) } }

9/9


更多相关文章:

非常超级学习网 fccjxxw.com

copyright ©right 2010-2021。
非常超级学习网内容来自网络,如有侵犯请联系客服。zhit325@126.com|网站地图