Go reflect初探

Go reflect初探在计算机科学中 反射是指计算机程序在运行时 Runtime 可以访问 检测和修改它本身状态或行为的一种能力 用比喻来说 那种程序能够 观察 并且修改自己的行为 要注意反射和内省 typeintrospe 的区别 对应于变量 也就是围绕着它的类型 type 和值 value 进行展开 Go 的空接口概念 反射可以发挥很大的威力 两个重要类型 reflect Type re

两个重要类型

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

Type的一些方法

  • String
  • Name 都以字符串的形式返回结构名,只是Name包括包名
  • Field(index) 根据索引获得字段,返回的是StructField(字段也有类型,当然包含一个reflect.Type的字段)
  • NumField 返回的结构的字段数
  • FieldByName 根据字段名获得字段

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

type Foo struct { X string Y int } func main() { var q = Foo{} var f interface{} = q t := 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 = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer )

大体可以这样使用

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{ 
   } = q t := 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{ 
   } = &q reflect.ValueOf(f).Elem().Field(0).SetString("4321") fmt.Println(q)// output:{4321 123} } 

练习:怎么给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.ms 138.ms

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232547.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • MATLAB下载+安装教程[通俗易懂]

    MATLAB下载+安装教程[通俗易懂]MATLAB下载+安装教程说明:本文章提供的是MATLAB2018b的下载及安装方式。下载2个DVD镜像然后对其进行安装操作,本人亲测有效。下载提供的是百度网盘的下载,暂时没有找到其他途径的下载方式,后续若有其他下载方式在更新提供给各位网友。链接:https://pan.baidu.com/s/1Ph5KZdABQmM_sjyOVC7WMg提取码:rd9a下载资源一共有3个:DVD1+DVD2+MATLAB_R2018b_Win64_Crack安装安装全过程将电脑上的杀毒软件关闭,

    2022年6月2日
    52
  • python删除文件指定行

    python删除文件指定行我们现在有五行数据,我们想删除第三行:pig删除文本指定行:删除文本指定行用的是foriini,找到指定行的关键字,将不包括关键字的其他行放在生成器中,将生成器包含的内容重新写入文件。我们这里不用readlines是因为foriinf是使用一行读取一行,不会消耗太多的内存。如果使用readlines就会一次性将所有的内容全部读取出来放在内存当中,会占用较多的内存,且不方便我们对…

    2022年5月30日
    166
  • 蓝桥杯历年真题及详细解答

    蓝桥杯历年真题及详细解答这里是蓝桥杯历年的题目汇总,后面将会陆续更新将往年真题以及解答发布出来,目前先更新C语言B组的,欢迎各位小伙伴关注我吖,你们的关注就是给我最好的动力!!!蓝桥杯历年省赛真题Java语言A组省赛真题Java语言B组省赛真题C语言A组省赛真题C语言B组省赛真题Java语言A组省赛真题2012第三届JavaA组蓝桥杯省赛真题2013第四届JavaA组蓝桥杯省赛真题2014第五届JavaA组蓝桥杯省赛真题2015第六届JavaA组蓝桥杯省赛真题2016第七届JavaA组蓝.

    2022年7月16日
    16
  • 如何解决eclipse乱码问题?「建议收藏」

    如何解决eclipse乱码问题?「建议收藏」方法一:代码里面进行改变编码1.编码方式的gbk和utf不同,不可以互相转换,只有byte和utf或者byte和gbk之间的转换,之间的转码如下:2.我们还可以使用另一种转码方式来转码,具体如下:3.如果这两种方法,你都试验过,还没有转码成功的话,那就要看看你的控制台或者页面编码方式了:方法二:编码方式,控制台修改1.Window->Preferences…

    2022年5月25日
    34
  • 学习Java大数据需要掌握哪些Java技能?

    学习Java大数据需要掌握哪些Java技能?学习Java大数据需要掌握哪些Java技能?现在大数据发展很速度很多小伙伴想要学习Java大数据技术开发,但是学习大数据为什么需要掌握Java技能呢?一、学大数据为什么要掌握Java?首先,我们学习大数据,为什么要先掌握Java技术?Java是目前使用非常广泛的编程语言,它具有的众多特性,特别适合作为大数据应用的开发语言。Java不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的

    2022年5月27日
    31
  • 一张图理清SpringMVC工作原理

    一张图理清SpringMVC工作原理一、首先,我们先来认识一下SpringMVC的主要组件前端控制器(DisatcherServlet):接收请求,响应结果,返回可以是json,String等数据类型,也可以是页面(Model)。处理器映射器(HandlerMapping):根据URL去查找处理器,一般通过xml配置或者注解进行查找。处理器(Handler):就是我们常说的controller控制器啦,由程序员编写。处理器适配器(Ha

    2022年5月14日
    46

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号