Go笔记之反射

栏目: Go · 发布时间: 6年前

内容简介:Reflection(反射)在计算机中表示程序能够检查自身结构的能力,尤其是类型;它是元编程的一种形式;golang的反射性能不理想,原因:

Reflection(反射)在计算机中表示程序能够检查自身结构的能力,尤其是类型;它是元编程的一种形式;

interface与反射

  • 变量由 (type,value) 类型 两部分组成;
  • 类型Type包括 static type 静态类型与 concrete type 具体类型;

    静态类型即指 go 语言编码中指定的类型,如int、string
    具体类型指运行时runtime系统看见的类型
    
  • 类型断言取决于 具体类型 而不是 静态类型 ;

  • 反射永远指的是interface类型,而非go语言指定的静态类型;
  • 每个interface变量实现中都有一个对应的pair,即记录了实际变量的值与类型的键值对: (value, type)
  • interface{} 包含两个指针,一个指向值的类型 concrete type ,一个指向实际的值 value
  • 反射 就是用来检测存储在接口变量内部pair对 (value, concrete type) 的一种机制;

反射reflect基本功能TypeOf和ValueOf

  • reflect.ValueOf()reflect.TypeOf() 用于访问接口变量pair中的value及type;

    // ValueOf用来获取输入参数接口中的数据的值,如果接口为空则返回0
    func ValueOf(iinterface{})Value {...}
    
    // TypeOf用来动态获取输入参数接口中的值的类型,如果接口为空则返回nil
    func TypeOf(iinterface{})Type {...}
    
  • 反射类型变量 reflect.Typereflect.Value

    通过执行reflect.ValueOf(interface),将会返回一个类型为reflect.Value的变量
    通过执行reflect.TypeOf(interface),将会返回一个类型为reflect.Type的变量
    
  • 反射类型转换为真实类型有两种情况

    > 情况1. 已知原有类型(使用类型断言强制装换)
    
    `reflect.Value`变量可以通过其本身`interface()`方法获取接口变量真实内容,然后再通过类型断言进行转换,转换为原来的真实类型;
    
    大致过程即: 反射类型 -> 接口类型 -> 真实类型
    
    realValue := reflectValue.Interface().(已知的类型)
    注意:类型断言中的预转换类型应该与已知类型一致,否则会触发Panic;
    
    > 情况2. 未知原有类型(遍历探测其Filed及Method)
    
    > 2.1. 获取未知类型的interface的具体变量及其类型的步骤为:
    
    1) 先获取interface的reflect.Type,然后通过NumField进行遍历
    2) 再通过reflect.Type的Field获取其Field
    3) 最后通过Field的Interface()得到对应的value
    
    > 2.2. 获取未知类型的interface的所属方法(函数)的步骤为:
    
    1) 先获取interface的reflect.Type,然后通过NumMethod进行遍历
    2) 再分别通过reflect.Type的Method获取对应的真实的方法(函数)
    3) 最后对结果取其Name和Type得知具体的方法名
    

通过reflec.Value设置实际变量的值

reflect.Value 是通过 reflect.ValueOf(X) 获得的,只有当X是指针的时候,才可以通过 reflec.Value 修改实际变量X的值,即:要修改反射类型的对象就一定要保证其值是可寻址 addressable 的;

var pi float64 = 3.1415
poiner := reflect.ValueOf(&pi)
newVal := poiner.Elem()
newVal.Type() // float64
newVal.CanSet() // true
newVal.SetFloat(1.618)
  • 当修改实际变量值时,reflect.ValueOf的传参必须为指针;
  • relect.Value通过Elem()方法获取原始值对应的反射对象, 如果传入的非指针调用Elem()会Panic;
  • 通过CanSet()方法判断是否可修改设置,如果传入的非指针则返回false;

通过reflect.ValueOf来进行方法的调用

  • 要通过反射来调用起对应的方法,必须先通过reflect.ValueOf(interface)获取reflect.Value,得到“反射类型对象”后才能做下一步处理;

  • 通过reflect.Value.MethodByName(funcName)方法注册并获取调用方法,需要注意的是,必须传入准确真实的方法名称,如果错误将直接panic,MethodByName返回一个函数值对应的reflect.Value方法的名字。

  • []reflect.Value作为最终需要调用的方法的参数,可以没有或者一个或者多个,根据实际参数来定。

  • reflect.Value的Call()方法,通过反射方式最终调用真实的方法,参数务必保持一致;

反射reflect性能

golang的反射性能不理想,原因:

  • reflect视线中存在大量的枚举,即for循环,如类型等;
  • reflect涉及到内存分配及后续的垃圾回收GC;

小结

  • 反射提高的程序的灵活性,使得interface{}发挥更大作用

    反射必须结合interface类型,也即是说变量的类型Type必须是具体类型concrete type;

  • 反射可以将 接口类型变量 转换为 反射类型变量
    通过反射的 TypeOfValueOf 方法将接口变量转为反射变量;

  • 反射也可将 反射类型变量 转换为 接口类型变量

    在已知类型情况下通过 reflect.value.Interface().(已知的类型) 方式转换接口类型变量;

    在未知类型情况下通过遍历reflect.Type的Field然后通过Field.Interface()获取接口类型变量;

  • 反射可以修改反射类型变量,但其值必须是可寻址的addressable

  • 通过反射可以动态的调用方法

参考阅读:


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

运营有道:重新定义互联网运营

运营有道:重新定义互联网运营

李明轩 / 机械工业出版社 / 2017-7-31 / 69.00元

本书是前百度资深运营专家多年运营经验的总结,是作者运营千万级用户规模的大型互联网产品的实操经验复盘,是作者在“在行”上为近百位CEO和高管提供互联网运营咨询服务后对互联网运营需求的深入洞见。 本书的思想基础是“运营必须以用户为中心”,从产品、用户、市场3个维度对互联网运营重新进行了系统性的梳理:从道的层面解读并重新定义运营方法论,从术的层面围绕方法论提出行之有效的解决方法和实际案例。重点不在......一起来看看 《运营有道:重新定义互联网运营》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具