反射

  • 基本概念
  • 反射规则
    • 反射API
    • 反射三定律
  • 反射优缺点
    • 优点
    • 缺点

基本概念

Go的反射基础是接口和类型系统。Go的反射借助了实例到接口的转换所使用的的数据结构,首先将实例传递给内部的空接口,实际上是将一个实例类型转换为接口可以表述的数据结构eface ,反射基于这个转换后的数据结构来访问和操作实例的值和类型。

在Golang的实现中,每个interface变量都有一个对应的pair,pair中记录了实际变量的值和类型:

 (value, type)

value是实际变量值,type是实际变量的类型。一个interface{}类型的变量包含两个指针,一个指针指向值的类型(对应concrete type),另外一个指针指向实际的值(对应value)。

interface及其pair的存在,是Golang中实现反射的前提,理解pair,就更容易理解反射。反射就是用来检测存储在接口变量内部(值value, 类型concrete type)pair对的一种机制。

反射规则

实例、value、type三者之间的转换关系如图所示

反射API

  1. 从实例到 Value
    通过实例获取Value对象,直接使用 reflect.ValueOf() 函数。例如

    func ValueOf(i interface{}) Value
    var x int = 100
    v := reflect.ValueOf(x)
    
  2. 从实例到 Type
    通过实例获取反射对象的Type,直接使用 reflect.TypeOf() 函数。例如

    func TypeOf(i interface{}) Type
    var x int = 100
    v := reflect.TypeOf()
    
  3. 从 Type 到 Value
    Type里边只有类型信息,所以直接从一个 Type 接口变量里边是无法获得实例的 Value 的,但可以通过该 Type 构建一个新实例的 Value。reflect 包提供两种方法,

    // New返回的是一个Value,该Value的type为PtrTo(typ),即Value的Type是指定的typ的指针类型
    func New(typ Type) Value// Zero 返回的是一个 typ 类型的零值,注意返回的 Value 不能寻址,值不可改变
    func Zero(typ Type) Value// 如果知道一个类型值的底层存放地址,则还有一个函数可以根据type和该地址值恢复出Value的
    func NewAt(typ Type, p unsafe.pointer) Value
    
  4. 从 Value 到 Type
    从反射对象 Value 到 Type 可以直接调用 Value 的方法,因为 Value 内部存放着到 Type 类型的指针。

    func (v Value) Type() Type
    
  5. 从 Value 到实例
    Value 本身就包含类型和值信息,reflect 提供了丰富的方法来实现从 Value 到实例的转换

    // 该方法最通用,用来将 Value 转换为空接口,该空接口内部存放具体类型实例
    // 可以使用接口类型查询去还原为具体的类型
    func (v Value) Interface() (i interface{})//Value 自身也提供丰富的方法,直接将 Value 转换为简单的类型实例, 如果类型不匹配,则直接引起panic
    func (v Value) Bool() bool
    func (v Value) Float() float64
    func (v Value) Int() int64
    func (v Value) Uint() uint64
    

    例如

    var x int = 123
    v := reflect.ValueOf(x)
    fmt.Println(x.Int())   // 123  值得注意的是类型首字母要大写,如 x.Int
    
  6. 从 Value 的指针到值
    从一个指针类型的 Value 获得值类型 Value 有两种方法

    // 如果 v类型是接口,则 Elem()返回接口绑定的实例的Value
    // 如果 v类型是指针,则返回指针的 Value,否则引起 painc
    func (v Value) Elem() Value// 如果 v 是指针,则返回指针值的 Value,否则返回 v 自身,该函数不会引起 panic
    func Indirect(v Value) Value
    
  7. Type 指针和值的相互转换
    1)指针类型Type到值类型Type

    // t 必须是Array、Chan、Map、Ptr、Slice,否则会引起panic
    // Elem返回的是其内部元素的Type
    t.Elem() Type
    

    2)值类型Type到指针类型Type

    // PtrTo 返回的是指向t 的指针型Type
    func PtrTo(t Type) Type
    
  8. Value值的可修改性
    Value 值的修改涉及如下两个方法

    // 通过CanSet判断是否能修改
    func (v Value) CanSet() bool
    // 通过Set进行修改
    func (v Value) Set(x Value)
    

    但是修改值一般要配合指针使用.
    例如:

    var x = 10
    v := reflect.ValueOf(&x)
    v.Elem().SetInt(20)  //v.Elem().Kind == int
    fmt.Println(x)  // 20
    
  9. 关于结构体的一些方法

    方法 说明
    Field(i int) StructField 根据索引返回对应的结构体字段信息
    NumField() int 返回结构体成员字段数量
    FieldByName(name string) (StructField, bool) 根据名字搜索是否有对应结构体字段信息并返回
    FieldByIndex(index []int) StructField 多层成员访问时,根据 []int 提供的每个结构体的字段索引,返回字段的信息
    FieldByNameFunc(match func(string) bool) (StructField,bool) 根据传入的匹配函数匹配需要的字段
    NumMethod() int 返回结构体方法数量
    Method(i int) Method 返回第i个方法
    MethodByName(string)(Method, bool) 根据方法名返回方法

反射三定律

  1. 反射可以将“接口类型变量”转换为“反射类型对象”
  2. 反射可以将“反射类型对象”转换为“接口类型变量”
  3. 如果要修改“反射类型对象”,其值必须是“可写的”(settable)

反射优缺点

优点

  1. 1.有时你需要编写一个函数,但是并不知道传给你的参数类型是什么,可能是没约定好;也可能是传入的类型很多,这些类型并不能统一表示。这时反射就会用的上了。
  2. 2.有时候需要根据某些条件决定调用哪个函数,比如根据用户的输入来决定。这时就需要对函数和函数的参数进行反射,在运行期间动态地执行函数。

缺点

  1. 与反射相关的代码,经常是难以阅读的。在软件工程中,代码可读性也是一个非常重要的指标。
  2. Go语言作为一门静态语言,编码过程中,编译器能提前发现一些类型错误,但是对于反射代码是无能为力的。所以包含反射相关的代码,很可能会运行很久,才会出错,这时候经常是直接panic,可能会造成严重的后果。
  3. 反射对性能影响还是比较大的,比正常代码运行速度慢一到两个数量级。所以,对于一个项目中处于运行效率关键位置的代码,尽量避免使用反射特性。

golang——反射相关推荐

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

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

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

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

  3. golang 反射_云原生的 Java与Golang

    > Photo by Raquel Martínez on Unsplash Java曾经著名的座右铭:"一次编写并在任何地方运行"如今已经过时了,我们想要运行代码的唯一地方 ...

  4. golang 反射_golang原理篇- nil:接口类型和值类型的区别

    interface接口类型是golang的最重要的数据结构,底层是value和type组成,实现interface的struct的实例都能赋值给接口类型的变量,实现动态value的能力.type记录v ...

  5. golang 反射_Golang 会淘汰 Python 吗?

    打开的第一件事就是星标公众号 然后扫码进群 作者 | Michael lyam译者 | 孙薇,责编 | 郭芮本文经授权转自公众号 CSDN(ID:CSDNnews)Golang和Python究竟哪种语 ...

  6. golang 反射 reflect包 struct相互填充

    最近在用Golang写一些简单的业务,经常需要在两类相似的结构体之间相互填充数据,如果struct只有少数几个field,相互赋值还好:struct有很多field的,实例代码如下: type Req ...

  7. golang 反射 reflect 设置 struct 字段

    目录 说明1 reflect.Value区分CanSet和Can not Set 说明2 将值转成reflect.Value类型 说明3  reflect.ValueOf 参数必须是一个 指针 或   ...

  8. golang 反射 获取 设置 结构体 字段值

    实例如下: type MyStruct struct {N int } n := MyStruct{ 1 }// get immutable := reflect.ValueOf(n) val := ...

  9. golang interface to string_Golang 反射

    原文作者:OhBonsai 来源:简书 基本了解 在Go语言中,大多数时候值/类型/函数非常直接,要的话,定义一个.你想要个Struct 1type Foo struct {2 A int 3 B s ...

最新文章

  1. 基带信号传输之信道均衡
  2. python写小程序-你用python写过那些好玩的微信小程序?
  3. 运用BT在centos下搭建一个博客论坛
  4. 通过图片优化,我将网站大小减少了62%
  5. linux中here文档,Linux下Bash Heredoc(Here document)的用法及基本示例
  6. 计算智能-群智能算法-蚁群算法matlab实现
  7. 一个基于cocos2d-x 3.0和Box2d的demo小程序
  8. 如何理解 Linux 中的 load averages
  9. java dns 解析域名解析_java网络学习 java dns 域名解析协议实现
  10. ASP.NET2.0网站配置的数据库连接失败问题(zz)
  11. 帮Python找“对象”
  12. 【刷题】BZOJ 4503 两个串
  13. 终于解决了x64 win7上运行金山词霸的问题
  14. “隐身侠”轻松破解,忽略开关机保护
  15. 如何解除禁用 UAC
  16. Android Camera聚焦区域和测光区域的设置
  17. 一款网页游戏外挂开发-数据抓包2
  18. 【翻译】Kinect v2程序设计(C++) Depth编
  19. NumPy与ndarray简介
  20. 人工智能,达尔文进化论

热门文章

  1. GVS视声挺进西藏,为阿里地区人民医院打造全时高效智慧医疗体验
  2. 预科知识整理【计算机、硬件、软件、快捷键、Dos命令】
  3. java利用高德地图解析经纬度字符串所在的城市
  4. linux 多用户ftp服务器的架设,用Linux架设FTP服务器(1)分享
  5. Apple 词典·再要你命 3000 | 美国传统大辞典 | Merriam Webster Collegiate Dict
  6. flash小游戏在Kongregate上线——BasketBall Master(篮球大师)
  7. 显卡用电测试软件,自己动手DIY!教你如何实测显卡电压!
  8. springboot启动报错:create a memory leak. Stack trace of thread:(DubboResponseTimeoutScanTimer)
  9. java计算机毕业设计作业自动评阅系统的设计和开发源程序+mysql+系统+lw文档+远程调试
  10. 支付宝二维码可以抓包更改金额_好消息!潍坊人也可以手机扫码坐公交啦!