在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本
身状态或行为的一种能力。用比喻来说,那种程序能够“观察”并且修改自己的行为。要注意反射和内省(type introspection)的区别。

对应于变量,也就是围绕着它的类型(type)和值(value)进行展开。
Go的空接口概念+反射可以发挥很大的威力>_<

两个重要类型

  • reflect.Type(reflect.Typeof()获得)
  • reflect.Value(reflect.Value()获得)

Type的一些方法

  • String
  • Name 都以字符串的形式返回结构名,只是Name包括包名

  • Field(index) 根据索引获得字段,返回的是StructField(字段也有类型,当然包含一个reflect.Type的字段)

  • NumField 返回的结构的字段数

  • FieldByName 根据字段名获得字段

带Field的方法是获取结构体字段信息的。

type Foo struct {X stringY int
}
func main() {var q = Foo{}var f interface{} = qt := reflect.TypeOf(f)for i := 0; i < t.NumField(); i++ {field := t.Field(i)fmt.Println(field.Name, field.Type.Name())// output: X Y  string int}fi, _ := t.FieldByName("Y")fmt.Println(fi.Name)                output: Y
}

结构体不光有字段,还有方法,所以Go也提供了Method的一系列函数
- NumMethod
- Method
- FieldByNameFunc

Kind方法 返回对象的基本类型,如果是个结构体就返回struct。
有如下基本返回值

const (Invalid Kind = iotaBoolIntInt8Int16Int32Int64UintUint8Uint16Uint32Uint64UintptrFloat32Float64Complex64Complex128ArrayChanFuncInterfaceMapPtrSliceStringStructUnsafePointer
)

大体可以这样使用

func main() {var q = []int{1, 2, 3, 4}f := reflect.ValueOf(q)if f.Kind() == reflect.Slice {if fv, ok := f.Interface().([]int); ok {fmt.Println(fv)}}
}

Value的一些方法

Value更关注的是接口值,而不是类型的值

  • Field 返回的仍是一个Value
  • Interface 获得接口值,+ 断言进行类型转换
  • NumField 同上Type
func main() {var q = Foo{"1234", 123}var f interface{} = qt := reflect.ValueOf(f)for i := 0; i < t.NumField(); i++ {field := t.Field(i)fmt.Println(field.Interface())}field := t.Field(0)v, _ := field.Interface().(string)fmt.Println(v)
}

可以看到Value和Type有类似的地方
但我们有对改变Value的需求,很少有改变Type的需求。所以Value会有跟多的方法

一系列Set操作

  • Set
  • SetString
  • SetBytes
  • SetInt

  • 但是没有提供SetSlice >_<!
func main() {var q = Foo{"1234", 123}var f interface{} = &qreflect.ValueOf(f).Elem().Field(0).SetString("4321")fmt.Println(q)// output:{4321 123}
}

如何设置一个结构体? 首先一定要传入的是地址。
其次,使用Elem()方法,才能再去想办法获得字段。
最后要做类型断言和CanSet判断。(不能像我上面一样>_<)


练习:怎么给slice加一个Insert方法呢?而不用丑陋的两次append….

**解答**
func Insert(slice interface{}, pos int, value interface{}) interface{} {v := reflect.ValueOf(slice)ne := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(value)), 1, 1)ne.Index(0).Set(reflect.ValueOf(value))v = reflect.AppendSlice(v.Slice(0, pos), reflect.AppendSlice(ne, v.Slice(pos, v.Len())))return v.Interface()
}
func main() {slice := []int{1, 2}fmt.Println(Insert(slice, 1, 99))slice2 := []string{"a", "c", "d"}slice2 = Insert(slice2, 0, "b").([]string)fmt.Println(Insert(slice2, 4, "e"))
}

做下性能测试:

func Insert(slice interface{}, pos int, value interface{}) interface{} {v := reflect.ValueOf(slice)ne := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(value)), 1, 1)ne.Index(0).Set(reflect.ValueOf(value))v = reflect.AppendSlice(v.Slice(0, pos), reflect.AppendSlice(ne, v.Slice(pos, v.Len())))return v.Interface()
}
func main() {slice := []int{}slice2 := []int{}t0 := time.Now()for i := 1; i < 10000; i++ {slice = append(slice[:0], append([]int{i}, slice[0:]...)...)}t1 := time.Now()for i := 1; i < 10000; i++ {slice2 = Insert(slice2, 0, i).([]int)}t2 := time.Now()fmt.Println(t2.Sub(t1), t1.Sub(t0))}

输出:

215.283082ms 138.150966ms

连续插入一万个,使用反射和不使用消耗时间差了一倍。但我觉得还是可以接受的。>_<….对于性能要求不高的的地方,用用反射也没什么不可啊!

Go reflect初探相关推荐

  1. gRPC编码初探(java)

    背景:gRPC是一个高性能.通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众 ...

  2. UE4高级功能--初探超大无缝地图的实现LevelStream

    转:原地址:http://blog.csdn.net/pizi0475/article/details/49004383 UE4高级功能--初探超大无缝地图的实现LevelStream 前言 好吧,这 ...

  3. 2021年大数据Flink(九):Flink原理初探

    Flink原理初探 Flink角色分工 在实际生产中,Flink 都是以集群在运行,在运行的过程中包含了两类进程. JobManager: 它扮演的是集群管理者的角色,负责调度任务.协调 checkp ...

  4. 从壹开始微服务 [ DDD ] 之一 ║ D3模式设计初探 与 我的计划书

    缘起 哈喽大家周四好!又是开心的一天,时间过的真快,我们的 <从壹开始 .net core 2.1 + vue 2.5 >前后端分离系列共 34 篇已经完结了,当然以后肯定还会有更新和修改 ...

  5. 经典算法研究系列:二、Dijkstra 算法初探

    经典算法研究系列:二.Dijkstra 算法初探  July   二零一一年一月 ====================== 本文主要参考:算法导论 第二版.维基百科. 写的不好之处,还望见谅. 本 ...

  6. Java IDEA import sun.reflect.ConstructorAccessor报错

    Java IDEA import sun.reflect.ConstructorAccessor报错 问题 解决 问题 报错如下图,发现是jdk版本的原因,如下是jdk: 11.0.6报错截图 解决 ...

  7. Golang反射机制的实现分析——reflect.Type方法查找和调用

    在<Golang反射机制的实现分析--reflect.Type类型名称>一文中,我们分析了Golang获取类型基本信息的流程.本文将基于上述知识和经验,分析方法的查找和调用.(转载请指明出 ...

  8. Golang反射机制的实现分析——reflect.Type类型名称

    现在越来越多的java.php或者python程序员转向了Golang.其中一个比较重要的原因是,它和C/C++一样,可以编译成机器码运行,这保证了执行的效率.在上述解释型语言中,它们都支持了&quo ...

  9. Golang的反射reflect深入理解和示例

    [TOC] Golang的反射reflect深入理解和示例 [记录于2018年2月] 编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机 ...

  10. 用es6 (proxy 和 reflect)轻松实现 观察者模式

    js中 观察者 之前我们一般通过事件机制完成 ex: 注册监听 Event.listen('changeName', name => console.log(name)) 派发事件 Event. ...

最新文章

  1. linux的挂载命令
  2. 实验23:测试泛型依赖注入★
  3. 处理微信文章中防盗链问题
  4. boost::mp11::mp_max相关用法的测试程序
  5. a commit git 参数是什么意思_深入理解Git - 一切皆commit
  6. Andriod: 在xml布局中使用自定义属性
  7. 网站随机动态密码代码
  8. SDL附着window窗口的方法
  9. Hadoop各个组件与端口
  10. oracle隐含参数 开库,Oracle数据库隐含参数介绍
  11. 网络操作系统之VyOS部署
  12. React+antd动态增加Table可编辑行
  13. 二级域名映射服务器,如何进行二级域名解析做端口映射?
  14. 生信入门(二)fastqc 生成的.html解读
  15. 生存分析第四课:Cox Proportional hazards model
  16. 街头篮球服务器未响应,我的生涯我做主 《街头篮球》生涯联赛FAQ
  17. 保研面试/考研复试高等数学问题整理
  18. 机器学习基础 EM算法
  19. 【无标题】UOS显示仓库https://professional-packages.chinauos.com/desktop-professional 没有数字签名
  20. FusionCharts的基本使用(3)

热门文章

  1. 半导体设备英文缩写_涨知识!晶圆制造主要设备一览。
  2. 2015—2016年QS世界大学排名200强-[转]
  3. PHP accesstoken失效,微信开发-ACCESS TOKEN 过期失效解决方案
  4. 舞伴配对问题c语言实训报告,数据结构-舞伴配对实训.docx
  5. 甲醛测量仪 DART WZ-S + stm32f103c + stmDuino IDE + I2C OLED
  6. 神经元图片结构图,一个神经元简图
  7. ImageView实现圆形头像效果
  8. Quartus II 13.1 出现 ‘‘can‘t find design entity <Filename>‘‘ 问题的解决方法
  9. 【NOI2011】 阿狸的打字机(AC自动机+树状数组)
  10. 逆水寒服务器维护中,逆水寒维护到几点今天 逆水寒11.1更新了什么