下面由golang教程栏目给大家介绍详解golang的反射(实例),希望对需要的朋友有所帮助!
前言
反射在很多语言中都有其妙用。在计算机科学领域,反射是指一类应用,它们能够*自描述*和*自控制*。
本文将记录笔者对于golang的反射的笔记。
10s后,以下知识点即将靠近:
1.反射的简介
2.为什么使用反射?
3.反射具体能做什么
正文1.反射的简介
golang提供了一种机制,在编译时不知道类型的情况下,可更新变量、运行时查看值、调用方法以及直接对他们的布局进行操作的机制,称为反射。
2.为什么使用反射?
打个比方,有时候我们需要一个函数可以处理各种类型的值。在不知道类型的情况下,你可能会这么写:
// 伪代码switch value := value.(type) {case string: // ...一些操作case int: // ...一些操作 case cbsstruct: // 自定义的结构体 // ...一些操作// ...}有没发现什么问题?
这边存在一个问题:类型很多,这个函数会写的非常长,而且还可能存在自定的类型,也就是说这个判断日后可能还要一直改,因为无法知道未知值到底属于什么类型。
无法透视一个未知类型的时候,以上代码其实不是很合理,这时候就需要有反射来帮忙你处理,反射使用typeof和valueof函数从接口中获取目标对象的信息,轻松完成目的。
3.反射具体能做什么?
1.获取变量内部信息
reflect提供了两种类型来进行访问接口变量的内容:
类型作用reflect.valueof()获取输入参数接口中的数据的值,如果为空则返回0 <- 注意是0reflect.typeof()动态获取输入参数接口中的值的类型,如果为空则返回nil <- 注意是nil
上代码
package mainimport ( "fmt" "reflect")func main() { var name string = "咖啡色的羊驼" // typeof会返回目标数据的类型,比如int/float/struct/指针等 reflecttype := reflect.typeof(name) // valueof返回目标数据的的值,比如上文的"咖啡色的羊驼" reflectvalue := reflect.valueof(name) fmt.println("type: ", reflecttype) fmt.println("value: ", reflectvalue)}输出:
type: stringvalue: 咖啡色的羊驼更深一层:在以上操作发生的时候,反射将“接口类型的变量”转为了“反射的接口类型的变量”,比如上文实际上返回的是reflect.value和reflect.type的接口对象。(可以根据ide跟踪一下相关函数返回类型便知)
2.struct的反射
package mainimport ( "fmt" "reflect")type student struct { id int name string}func (s student) hello(){ fmt.println("我是一个学生")}func main() { s := student{id: 1, name: "咖啡色的羊驼"} // 获取目标对象 t := reflect.typeof(s) // .name()可以获取去这个类型的名称 fmt.println("这个类型的名称是:", t.name()) // 获取目标对象的值类型 v := reflect.valueof(s) // .numfield()来获取其包含的字段的总数 for i := 0; i < t.numfield(); i { // 从0开始获取student所包含的key key := t.field(i) // 通过interface方法来获取key所对应的值 value := v.field(i).interface() fmt.printf("第%d%u4e2a字段是:%s:%v = %v \\\\n", i 1, key.name, key.type, value) } // 通过.nummethod()来获取student里头的方法 for i:=0;i<t.nummethod(); i { m := t.method(i) fmt.printf("第%d%u4e2a方法是:%s:%v\\\\n", i 1, m.name, m.type) }}输出:
这个类型的名称是: student第1个字段是:id:int = 1 第2个字段是:name:string = 咖啡色的羊驼 第1个方法是:hello:func(main.student)3.匿名或嵌入字段的反射
package mainimport ( "reflect" "fmt")type student struct { id int name string}type people struct { student // 匿名字段}func main() { p := people{student{id: 1, name: "咖啡色的羊驼"}} t := reflect.typeof(p) // 这里需要加一个#号,可以把struct的详情都给打印出来 // 会发现有anonymous:true,说明是匿名字段 fmt.printf("%#v\\\\n", t.field(0)) // 取出这个学生的名字的详情打印出来 fmt.printf("%#v\\\\n", t.fieldbyindex([]int{0, 1})) // 获取匿名字段的值的详情 v := reflect.valueof(p) fmt.printf("%#v\\\\n", v.field(0))}输出:
reflect.structfield{name:"student", pkgpath:"", type:(*reflect.rtype)(0x10aade0), tag:"", offset:0x0, index:[]int{0}, anonymous:true}reflect.structfield{name:"name", pkgpath:"", type:(*reflect.rtype)(0x109f4e0), tag:"", offset:0x8, index:[]int{1}, anonymous:false}main.student{id:1, name:"咖啡色的羊驼"}4.判断传入的类型是否是我们想要的类型
package mainimport ( "reflect" "fmt")type student struct { id int name string}func main() { s := student{id: 1, name: "咖啡色的羊驼"} t := reflect.typeof(s) // 通过.kind()来判断对比的值是否是struct类型 if k := t.kind(); k == reflect.struct { fmt.println("bingo") } num := 1; numtype := reflect.typeof(num) if k := numtype.kind(); k == reflect.int { fmt.println("bingo") }}输出:
bingobingo5.通过反射修改内容
package mainimport ( "reflect" "fmt")type student struct { id int name string}func main() { s := &student{id: 1, name: "咖啡色的羊驼"} v := reflect.valueof(s) // 修改值必须是指针类型否则不可行 if v.kind() != reflect.ptr { fmt.println("不是指针类型,没法进行修改操作") return } // 获取指针所指向的元素 v = v.elem() // 获取目标key的value的封装 name := v.fieldbyname("name") if name.kind() == reflect.string { name.set
机器学习云服务器租用服务器网络速度慢-市场咨询把电脑屏幕投影到电视机大屏幕上的方法新疆云服务器租用公司上海高性能云服务器配置是什么云服务器租用什么叫云服务器证券类APP拉新的6个方法无法访问公司官网-云服务器问题