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

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

参考阅读:


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

查看所有标签

猜你喜欢:

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

知识发现

知识发现

史忠植 / 2011-1 / 59.00元

《知识发现(第2版)》全面而又系统地介绍了知识发现的方法和技术,反映了当前知识发现研究的最新成果和进展。全书共分15章。第1章是绪论,概述知识发现的重要概念和发展过程。下面三章重点讨论分类问题,包括决策树、支持向量机和迁移学习。第5章阐述聚类分析。第6章是关联规则。第7章讨论粗糙集和粒度计算。第8章介绍神经网络,书中着重介绍几种实用的算法。第9章探讨贝叶斯网络。第10章讨论隐马尔可夫模型。第11章......一起来看看 《知识发现》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具