Golang 反射应用及源码分析
reflect简介
- reflect 是指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力
- 用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
- reflect 实现了运行时的反射能力,能够让程序操作不同类型的对象。
- 反射作为一种元编程方式可以减少重复代码,但使用不当,也会使程序变得过于抽象,难以理解,且运行缓慢。因此我们需要对反射有一个基本的了解,以便能够恰当的使用反射。
什么时候需要反射
- 不能预先确定参数的类型,可能是因为没有约定好,也可能是传入的参数类型有很多,且不能统一表示。
- 函数需要根据输入的参数来动态的执行不同的行为
反射的优缺点
反射的优点
- 可以在一定程度上避免硬编码,提供灵活性和通用性。
- 可以作为一个第一类对象发现并修改源代码的结构(如代码块、类、方法、协议等)。
反射的缺点
- 同样因为反射的概念和语法都比较抽象,滥用反射会使得代码难以被其他人读懂
- 无法在编译时检查错误。作为一种强类型的语言,go 的编译器会在编译阶段检查出类型错误,但是 interface 定义的类型是不明确的,代码在运行时存在 panic 的风险
- 降低了代码运行的效率,反射出变量的类型需要额外的开销
反射三大定律
- Reflection goes from interface value to reflection object.
- Reflection goes from reflection object to interface value.
- To modify a reflection object, the value must be settable.
Reflection goes from interface value to reflection object.
从接口值
反射到反射对象
。
- 从 interface{} 变量可以反射出 reflect 对象,
- 具体来说,通过 reflect.TypeOf 获取了变量的类型,reflect.ValueOf 获取了变量的值。
- 如果我们知道了一个变量的类型和值,那么就意味着我们知道了这个变量的全部信息。通过 type、value 提供的方法,可以获取变量实现的方法、类型的全部字段等等。
1 | package reflect_test |
Reflection goes from reflection object to interface value.
从反射对象
变回 interface{}对象
- 具体来说,通过 Interface()方法 从反射对象获取interface{} 变量
To modify a reflection object, the value must be settable.
要更新一个 reflect.Value,那么它的值必须是可被更新的。否则将会导致 panic。
辅助判断:
- reflect.flag.mustBeAssignable 检查是否可以被设置
- reflect.flag.mustBeExported 检查变量是否可以被导出,防止不可导出的的变量泄露
- reflect.Value.assignTo 会返回一个新的反射对象,这个返回的反射对象指针会直接覆盖原反射变量