TOC
1. 什么是reflect?
反射是指在运行期对程序本身进行访问和修改的能力。程序编译后,变量被转换为内存地址,而变量名无法被编译器写入可执行部分。在运行程序时,程序无法获取自身的信息。
支持反射的语言可以在编译器将变量的反射信息如字段名称、类型信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样可以在程序运行期获取类型的反射信息, 并修改他们。
反射:反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力
Go使用reflect包访问程序的反射信息。
- 支持反射的语言:Go、Java、C#,而C/C++没有反射功能。
- Lua,JavaScript动态语言,可以在运行期访问程序自身的值与类型,故不需要反射特性
Go提供了一种在运行时更新和检查变量的值、调用变量的方法的机制,但在编译器不知道这些变量的具体类型,这种机制被称为反射
2. reflect 使用场景
示例1:
示例2:
interface类型值
3. reflect 实现原理
interface
3.1 反射的基础: interface{}
interface{} 存储结构
go 的接口是由两部分组成的,一部分是类型信息,另一部分是数据信息。
bint1bb
befacesrc/runtime/runtime2.go
一个 interface{} 中实际上既包含了变量的类型信息,也包含了类型的数据。
3.2 反射对象 reflect.Type & reflect.Value
- reflect.TypeOf :返回反射类型(returns the reflection Type that represents the dynamic type of i)
- reflect.ValueOf:返回反射值(returns a new Value initialized to the concrete value)
接口类型变量反射类型对象
reflect.TypeOf() 源码:
reflect.ValueOf() 源码:
TypeOfValueOfinterface{}reflect.Typereflect.Valuereflect.TypeOfreflect.ValueOf
3.3 反射定律
在 go 官方博客中关于反射的文章 laws-of-reflection 中,提到了三条反射定律:
interfaceinterfaceCanSet
关于这三条定律,官方博客已经有了比较完整的阐述,感兴趣的可以去看一下官方博客的文章。这里简单阐述一下:
interface
上文中举的例子中已经有了很清楚的表示,就不再举例了。
interface
reflect.Value.Interfaceinterfacereflect.ValueOfinterface{}
CanSet
reflect.Value.CanSetreflect.Value.Set
可设置要求:
- 反射对象是一个指针
- 这个指针指向的是一个可设置的变量
原因:
如果这个值只是一个普通的变量,这个值实际上被拷贝了一份。如果通过反射修改这个值,那么实际上是修改的这个拷贝的值,而不是原来的值。 所以 go 语言在这里做了一个限制。
v.CanSet() == false
vv.Elem()
x
v.CanSet()false
示例
4. 常用的方法
4.1 Elem
Elemelementreflectreflect.Type的Elemreflect.Value
reflect.Type 的 Elem 方法
reflect.TypeElemreflect.Type
Elemreflect.TypeElempanic
mapkeyKeyElem
reflect.Value 的 Elem 方法
reflect.ValueElem
上文中,修改反射对象章节中,有具体例子。
4.2 Interface 方法
获取反射对象的动态值。 也就是说,如果反射对象是一个指针,那么 Interface 方法会返回指针指向的值。
4.3 Kind 方法
Kind 表示的是 go 底层类型系统中的类型。
Kind
reflect.TypeKind
4.4 Type方法
reflect.Type
5. Reflect性能
首先我们来做一组测试:
我们可以通过以下的 benchmark 来对比一下:
addAny()addInt64()
慢的原因:
反射interface{}FieldByName
6. 总结
reflectinterface{}interface{}reflect.Typereflect.Valuereflect.Typereflect.ValueinterfaceinterfaceCanSetreflect.Valuereflect.TypeElemreflect.TypeElemarray、chan、map、pointerslicereflect.Typereflect.ValueElemreflect.Valuereflect.ValueInterfaceinterface{}TypeKindTypeKindint、string、struct