前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言之反射

Go语言之反射

作者头像
灰子学技术
发布2020-04-02 21:09:14
7160
发布2020-04-02 21:09:14
举报

笔者原本是C++开发人员,之前对于反射没太大概念,学了GO之后,才开始接触,在研究了一段时间之后,有了些认识,便整理一个帖子,希望对大家有所帮助。

在学习反射的时候,笔者一直在问自己,反射是什么?为什么要用到反射?它是怎么实现的?笔者觉得,在知道这些问题的答案之后,才算是真正了解反射。下面笔者便从这些问题来着手整理反射。

一、反射是什么?

维基百科上的定义:

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

《Go 语言圣经》中是这样定义反射的:

Go 语言提供了一种机制在运行时更新变量和检查它们的值、调用它们的方法,但是在编译时并不知道这些变量的具体类型,这称为反射机制。

通过上面的描述,我们能看出来,反射是“元编程”的一种实现手段,它表现在运行阶段,是对运行代码的一种再编译。

二、反射能干什么?

这里只是针对GO语言的反射来描述,反射主要用在下面两种情况下:

场景一: 参数的入参是空的interface,也就是说参数的入参需要在该函数被执行的时候,才能知道这个入参到底是什么类型。 这种情况产生的原因: 往往是函数定义的时候,希望该入参可以支持很多的数据类型,或者说定义该函数的时候,并没有想好这个入参应该是什么数据类型。 例如: json的序列化操作。 场景二: 程序在执行到一处代码的时候,它到底要调用哪一个函数,取决于当前传递的数据是什么规则,而不同的规则需要调用不同的函数,这种情况下也需要用到反射。 例如:webserver在接收到不同的uri的时候,需要使用不同的函数来处理,这就是很典型的一个例子。

所有的事情都有正反两面,反射也不例外,引入反射之后,会有下面的一些不好的地方:

1.代码可读性变低,对开发人员不是那么友好,阅读代码的难度上升一个层级。 2.反射使用后,会避过了编译阶段的类型检查,导致原本有可能在编译阶段发现的问题被隐藏掉。 3.反射对性能影响还是比较大的,比正常代码运行速度慢一到两个数量级,如果系统对性能要求很高,就需要慎用反射。

三、反射是怎么使用的?

在此之前,我们需要先看下,反射的三个定律,如下所示:

1.Reflection goes from interface value to reflection object.(反射能够将 interface 中的类型和值转换成真实的反射对象。) 2.Reflection goes from reflection object to interface value.(反射能够将真实的反射对象转变成真实类型。) 3.To modify a reflection object, the value must be settable.(如果像修改反射生成的反射对象,这个数值必须是可修改的。)

定律一:将空接口转换成反射对象

我们通过reflect.Typeof()来显示,真实的对象类型,例子如下:

func TypeOf(i interface{}) Type // Typeof()的定义可以看出参数是一个空的interface

我们通过reflect.ValueOf()来显示真实对象存储的数值,例子如下所示:

type Value struct {// contains filtered or unexported fields} func ValueOf(i interface{})Value // ValueOf的入参也是一个空接口

通过MethodByName来获取对应名称的函数,并调用

备注:GetName()原本只是一个返回值,但是输出结果却是[Hello]数组的原因是,Value.Call()函数的返回值是一个[]reflect.Value的数组。

定律二:将反射对象转换成原类型

reflect.ValueOf转换成的反射类型,可以通过Interface方法把它恢复成一个接口值,当然我们可以直接将这个接口值转换成对应的原数据,例子如下所示:

定律三:修改反射对象的值

reflect.ValueOf函数返回的是一份值的拷贝,所以直接对这个值进行修改是无意义的,因为它不会更改原来的那个值。

要想修改原来的数值,需要借用指针的特性,进行修改,这里也就是定律三中提到的可设置性,通过Elem()来找到对应的原数据值。

例子如下所示:

四、反射的原理是什么?

反射的实现是以空接口作为基础的,可以说空的接口是反射实现的基石。空接口类似于C语言中的void*,它可以转换成任何类型的数值。

当我们使用反射特性时,实际上用到的就是存储在 interface 变量中的和类型相关的信息,也就是常说的 <type, value>。

主要涉及到的数据结构和函数如下所示:


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 灰子学技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、反射是什么?
  • 二、反射能干什么?
  • 三、反射是怎么使用的?
  • 四、反射的原理是什么?
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档