反射reflection

  1. 反射可以大大的提高程序的灵活性,使得 interface{} 有更大的发挥余地

  2. 反射使用 TypeOf 和 ValueOf 函数从接口中获取目标对象信息

  3. 反射会将匿名字段作为独立字段(匿名字段本质)

  4. 想要利用反射修改对象状态,前提是 interface.data 是 settable,即 pointer-interface

  5. 通过反射可以“动态”调用方法

示例一:

  举例说明反射使用 TypeOf 和 ValueOf 来取得传入类型的属性字段于方法

package mainimport ("fmt""reflect"
)//定义一个用户结构体
type User struct {Id intName stringAge int
}//为接口绑定方法
func (u User) Hello() {fmt.Println("Hello World.")
}//定义一个可接受任何类型的函数(空接口的使用规则)
func Info(o interface{}) {t := reflect.TypeOf(o)    //获取接受到到接口到类型fmt.Println("Type:", t.Name())    //打印对应类型到名称(这是reflect中自带到)//Kind()方法是得到传入类型到返回类型;下面执行判断传入类型是否为一个结构体if k := t.Kind(); k != reflect.Struct {fmt.Println("传入的类型有误,请检查!")return}v := reflect.ValueOf(o)    //获取接受到到接口类型包含到内容(即其中到属性字段和方法)fmt.Println("Fields:")  //如何将其中到所有字段和内容打印出来呢?/**通过接口类型.NumField 获取当前类型所有字段个数*/for i := 0; i < t.NumField(); i++ {f := t.Field(i)            //取得对应索引的字段val := v.Field(i).Interface()    //取得当前字段对应的内容fmt.Printf("%6s: %v = %v\n", f.Name, f.Type, val)}/**通过接口类型.NumMethod 获取当前类型所有方法的个数*/fmt.Println("Method:")for i := 0; i < t.NumMethod(); i++ {m := t.Method(i)        //取得对应索引的方法fmt.Printf("%6s: %v\n", m.Name, m.Type)}
}func main()  {u := User{1, "OK", 12}Info(u)//Info(&u) 如果传入的是结构体的地址或指针(pointer-interface),那么在Info函数中的Kind方法进行判断时就会被拦截返回
}

运行结果如下:

1
2
3
4
5
6
7
Type: User
Fields:
    Id: int = 1
  Name: string = OK
   Age: int = 12
Method:
 Hello: func(main.User)

示例二:

  如何通过反射得道结构当中匿名或者嵌入字段

package mainimport ("fmt""reflect"
)//定义一个用户结构体
type User struct {Id intName stringAge int
}type Manager struct {User    //定义了一个匿名引用title string
}func main() {m := Manager{User: User{1, "OK", 15}, title: "123"}t := reflect.TypeOf(m)//取得类型中的字段是否为匿名字段fmt.Printf("%6v\n", t.Field(0))/**打印内容:{User main.User  0 [ 0] true},其中true表示是匿名类型那么想要取匿名类型中的字段又该怎么取呢?这里需要使用序号组,传入要取的切片即可*/fmt.Printf("%v\n", t.FieldByIndex([]int{0, 0}))/**其中上面切片传入的是{0, 0},1. 第一个0表示当前结构Manager取匿名User是第一个即为02. 第二个0表示取得的结构User中要取第一个元素Id相对于User来说也是第一个即为0,如果要取Name则需传入[]int{0, 1}那么既然可以取出来内容,那么我们就可以尝试着进行修改,怎么做呢?*/tchage := reflect.ValueOf(&m)    //想要修改和我们之前所说的传入值类型和指针类型是一致的,要想修改需要传入对应指针类型tchage.Elem().FieldByIndex([]int{0, 0}).SetInt(999) //传入指针需要通过 .Elem() 来取得对应的值内容,之后再想取哪个再继续使用序号组fmt.Println(tchage.Elem().FieldByName("title"))fmt.Println(tchage)
}

运行结果:

1
2
3
4
{  User        main.User             0 [     0]   true}
{Id  int  0 [0] false}
123
&{{999 OK 15} 123}

示例三:

  那么让我们来写一个比较完整的通过反射修改结构体内部字段内容

package mainimport ("fmt""reflect"
)//定义一个用户结构体
type User struct {Id intName stringAge int
}func main() {u := User{1, "OK", 13}fmt.Println(u)Set(&u)fmt.Println(u)
}//定义一个可以接受任何类型的空接口
func Set(o interface{}) {v := reflect.ValueOf(o)//通过反射修改类型中的内容需要传入指针,为了防止传入有误故在这里进行相关过滤验证判断(这前这快是已经说过的)if v.Kind() == reflect.Ptr && !v.Elem().CanSet() {//reflect.Ptr对应为指针类型;v.Elem().CanSet()取得对应地址下的内容并查看其是否可以进行修改fmt.Println("传入的类型有误,请检查!")return} else {v = v.Elem()    //将实际对象(包含详情内容)进行赋值}f := v.FieldByName("Name")f1 := v.FieldByName("Id1")if !f.IsValid() {    //判断通过名称获取得到到内容是否为空值fmt.Println("没有Name对应属性字段")return}if !f1.IsValid() {fmt.Println("没有Id1对应属性字段")}if f.Kind() == reflect.String {f.SetString("HelloWorld")}
}

运行结果:

1
2
3
{1 OK 13}
没有Id1对应属性字段
{1 HelloWorld 13}

示例四:

  那么让我们来写一个比较完整的通过反射对方法等动态调用

package mainimport ("fmt""reflect"
)//定义一个用户结构体
type User struct {Id intName stringAge int
}//为User绑定方法
func (u User) HelloDisplay(name string) {fmt.Println("Hello", name, " my name is ", u.Name)
}func main() {u := User{1, "OK", 29}u.HelloDisplay("jack") //正常调用/**以下方式为反射调用,最优到代码写法就是新写一个方法且在开始是通过kind判断类型是否正确且需要判断有没有对应方法等*/v := reflect.ValueOf(u)    //通过反射得到类型内容methodV := v.MethodByName("HelloDisplay")  //通过方法名称得道方法实体args := []reflect.Value{reflect.ValueOf("jack")}  //设置反射传入的参数methodV.Call(args)
}

运行结果:

1
2
Hello jack  my name is  OK
Hello jack  my name is  OK

GO语言基础之reflect反射相关推荐

  1. GO语言reflect反射篇

    1.1 reflect反射是什么,为什么需要反射 GO 反射的意义:Go 语言的 ORM 库离不开它,Go 语言的 json 序列化库离不开它, fmt包字符串格式化离不开它,Go 语言的运行时更是离 ...

  2. Java 语言基础(异常机制和File类,IO流,多线程,网络编程,反射机制)

    原文:Java 语言基础(异常机制和File类,IO流,多线程,网络编程,反射机制) 异常机制和File类 异常机制 基本概念 异常就是"不正常"的含义,在 Java 语言中主要指 ...

  3. Java基础10(反射)

    Java基础10(反射) 1 什么是反射 官方解释:反射(reflection)技术通常被用来检测和改变应用程序在 Java 虚拟机中的行为表现.它是一个相对而言比较高级的技术,反射是一种强有力的技术 ...

  4. Java基础13:反射与注解详解

    Java基础13:反射与注解详解 什么是反射? 反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. Orac ...

  5. golang快速入门--语言基础

    语言基础语法 行分隔符 在golang中,多个语句写在同一行,必须使用分号 " ; " 分隔开 注释 单行注释 使用// 即可表示 多行注释 使用/-/ 表示 字符串连接 允许使用 ...

  6. Go语言设计与实现 -- 反射

    Go的反射有哪些应用? IDE中代码的自动补全 对象序列化 fmt函数的相关实现 ORM框架 什么情况下需要使用反射? 不能明确函数调用哪个接口,需要根据传入的参数在运行时决定. 不能明确传入函数的参 ...

  7. go语言基础学习笔记完整版

    目录 背景 基础 helloworld 变量 常量 数据类型 基本数据类型与复杂数据类型 值类型与引用类型 查看变量类型 字符与字符串 类型转换 指针 打包 读取控制台数据 for-range遍历 生 ...

  8. Java基础-注解和反射

    Java基础-注解和反射 前言 对于注解,我主要还是在自定义APT还有运行时反射获取类来让自己能够构建出复用性更高的代码逻辑. 知识点1-注解: 注解的应用场景由元注解@Retention来进行指定, ...

  9. Java基础教程:反射基础

    Java基础教程:反射基础 引入反射 反射是什么 能够动态分析类能力的程序称为反射. 反射是一种很强大且复杂的机制. Class类 在程序运行期间,Java运行时系统始终为所有对象维护一个被称为运行时 ...

最新文章

  1. Ubuntu 14.04安装搜狗拼音linux版应该注意的问题
  2. ajax局部刷新后,如何让局部中的百度分享重新加载
  3. 大数据落地决胜的关键——百分点BASIC模型
  4. 我的学习之路_第二十三章_HTML
  5. SpringBoot快速集成kafka
  6. Java继承多态经典案例分享
  7. mysql自带的卸数工具_数据库卸数必备工具下载-数据库数据导出工具(DBexport)下载v1.3官方版-西西软件下载...
  8. dfa matlab用法,关于使用MF-DFA方法计算广义Hurst指数的MATLAB操作问题
  9. Python——常见数据类型的调试笔记(“如何通过Debug信息判断数据类型”)
  10. html弹出保存文件对话框_初步了解CAD的模板文件
  11. 重学AS3之基础知识重点记忆
  12. 多线程 + java nio 实现按行读取并处理超大文件
  13. 计算机内录,如何电脑内部录音,介绍一款可以录制电脑内部声音的工具
  14. 哪些Amazon erp是可以免费使用的?
  15. video.js在react中实现视频播放(video.js)
  16. 清理系统垃圾缓存BAT
  17. 托福高频真词List12 // 附托福TPO阅读真题
  18. linux脚本命令同时起多个命令行窗口
  19. Btree/B+tree原理及区别(详解)
  20. SDL编程入门(27)碰撞检测

热门文章

  1. mysql hive 内置函数_Hive中与时间相关的内置函数
  2. shell 判断_shell之条件判断和流程控制
  3. 按覆盖地理范围的不同计算机网络可分为,按网络覆盖的地理范围进行分类,计算机网络可以分为:...
  4. 公共端接正极还是负极_【动力电池大事记】现代摩比斯启动首批模组工厂,松下拟挪威建厂,200名车主起诉现代,密歇根大学开发锂金属固态电池及“无负极”工艺...
  5. java循环制作万年历,java使用Calendar制作万年历
  6. 高压放电与防静电塑料包装
  7. 一个简单的Apriltag,数字,动物水果分类器
  8. 第十六届全国大学生智能车竞赛-航天智慧物流创意组-技术培训
  9. 比Tiny YOLOv3小8倍,性能提升11个点,4MB的网络也能做目标检测
  10. TPF111视频信号放大器研究