45-Golang中的反射
创始人
2024-06-02 06:39:22
0

Golang中的反射

    • 基本介绍
    • 反射的应用场景
    • 反射重要的函数和概念
    • 快速入门
      • 案例一
      • 案例二
    • 反射注意事项和细节说明
    • 反射的最佳实践

基本介绍

  • 1.反射可以在运行的时候动态获取变量的各种信息,比如变量的类型,类别
  • 2.如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)
  • 3.通过反射,可以修改变量的值,可以调用关联的方法
  • 4.使用反射,需要import(“reflect”)

在这里插入图片描述

反射的应用场景

1.不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射

func bridge(funcPtr interface{}, args ...interface{})

例如以上这种桥接模式,第一个参数funcPtr以接口的形式传入函数指针,函数参数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数

2.对结构体序列化时,如果结构体有指定Tag,也会使用到反射生成对应的字符串。

反射重要的函数和概念

1.reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型

2.reflect.ValueOf(变量名),获取变量的值,返回reflect.Value类型reflect.Value是一个结构体类型。通过reflect.Value,可以获取到关于该变量的很多信息。

3.变量,intface{}和reflect.Value是可以相互转换的,这点在实际开发中,会经常使用到

在这里插入图片描述

在这里插入图片描述

快速入门

案例一

编写一个案例,演示对(基本数据类型,interface{},reflect.Value)进行反射的基本操作

package mainimport ("fmt""reflect"
)//专门演示反射
func reflectTest01(b interface{}) {//通过反射获取的传入的变量type,kind,值//1.现获取到reflect.TyperType := reflect.TypeOf(b)fmt.Println("rType=", rType)//2.获取到reflect.ValuerVal := reflect.ValueOf(b)n2 := 2 + rVal.Int() //此处的Int()表示拿到真正的valuefmt.Println("n2=", n2)fmt.Printf("rVal=5=%v rVal type=%T\n", rVal, rVal)//3、将rVal转换成interface{}iV := rVal.Interface()//将interface{}通过断言转化成需要的类型num2 := iV.(int)fmt.Println("num2=", num2)
}func main() {//编写一个案例//编写一个案例,演示对(基本数据类型,interface{},reflect.Value)进行反射的基本操作//先定义一个intvar num int = 100reflectTest01(num)
}
/*
rType= int
n2= 102                           
rVal=5=100 rVal type=reflect.Value
num2= 100   
*/

案例二

编写一个案例,演示对(结构体类型,interface{},reflect.Value)进行反射的节本操作

package mainimport ("fmt""reflect"
)//演示对结构体的反射
func reflectTest(b interface{}) {rTyp := reflect.TypeOf(b)fmt.Println("rType=", rTyp)rVal := reflect.ValueOf(b)iV := rVal.Interface()fmt.Printf("iv=%v iV type=%T", iV, iV)
}type Student struct {Name stringAge  int
}func main() {//定义一个student实例stu := Student{Name: "kunkun",Age:  25,}reflectTest(stu)
}
//rType= main.Student
//iv={kunkun 25} iV type=main.Student

反射注意事项和细节说明

1.reflect.Value.Kind,获取变量的类别,返回的是一个常量

2.Type是类型,Kind是类别,Type和Kind可能是相同的,也可能是不同的

比如:var num int = 10 num 的Type是int,Kind也是int

比如:var stu Student stu的Type是包名.Student,Kind是struct

3.使用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,比如x是int,那么就应该使用reflect.Value(x).int(),而不能使用其他的,否则报panic

5.通过反射的来修改变量,注意当使用SetXxx方法来设置需要通过对应的指针类型来完成,这样才能改变传入的变量的值,同样需要使用到reflect.Value.Elem()方法

package mainimport ("fmt""reflect"
)//通过反射,修改num int的值
//修改student的值func reflect01(b interface{}) {//获取到reflect.ValuerVal := reflect.ValueOf(b)rVal.Elem().SetInt(20)}func main() {var num int = 10reflect01(&num)fmt.Println("num=", num)
}
//rVal.Elem()用于获取指针指向变量,类似
//var num = 10
//var b *int =&num
//*b = 3//num = 20

反射的最佳实践

1.使用反射来遍历结构体的字段,调用结构体的方法,并获取结构体标签的值

package mainimport ("fmt""reflect"
)//定义了一个Monster结构体
type Monster struct {Name  string `json:"name"`Age   int    `json:"age"`Score float32Sex   string
}//方法,显示s的值
func (s Monster) print() {fmt.Println("---start---")fmt.Println(s)fmt.Println("---end---")
}//方法,返回两个数的和
func (s Monster) GetSum(n1, n2 int) int {return n1 + n2
}//方法,接受四个值,给s赋值
func (s Monster) Set(name string, age int, score float32, sex string) {s.Name = names.Age = ages.Score = scores.Sex = sex
}func TestStruct(a interface{}) {//获取reflect.Type类型typ := reflect.TypeOf(a)//获取reflect.Value类型val := reflect.ValueOf(a)//获取到a对应的类型kd := val.Kind()//如果传入的不是struct,就退出if kd != reflect.Struct {fmt.Println("expect struct")return}//获取到该结构体有几个字段num := val.NumField()fmt.Printf("struct has %d fields\n", num)for i := 0; i < num; i++ {fmt.Printf("Field %d: 值为=%v\n", i, val.Field(i))//获取到struct标签,注意需要通过reflect.Type来获取tag标签的值tagVal := typ.Field(i).Tag.Get("json")if tagVal != "" {fmt.Printf("Field %d: tag为=%v\n", i, tagVal)}}numOfMethod := val.NumMethod()fmt.Printf("struct had %d methods\n", numOfMethod)//var params []reflect.Value//方法的排序默认是按照函数名的排序 (ASSCII码)val.Method(1).Call(nil)//调用结构体的第一个方法var params []reflect.Valueparams = append(params, reflect.ValueOf(10))params = append(params, reflect.ValueOf(40))res := val.Method(0).Call(params) //传入的参数是[]reflect.Valuefmt.Println("res=", res[0].Int()) //返回结果,返回的结果是[]reflect.Value
}
func main() {//创建了一个Monster实例var a Monster = Monster{Name:  "kunkun",Age:   25,Score: 30.8,}//将Monster实例传递给TestStruct函数TestStruct(a)
}

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  1.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...