1、定义:反射就是程序能够在运行时动态地查看自己的状态,并且允许修改自身的行为。
2、底层类型和基础类型的区别在于,基础类型是抽象的类型划分,底层类型是针对每一个具体的类型来定义的,比如不同的 struct 类型在基础类型上都划归为 sturct 类型,但不同的 struct底层类型是不一样的。
3、反射规则
4、反射API
(1)分类
1. 实例到 Value:通过实例获取 Value 象,直接使用 reflect. ValueOf()函数,例如:
func ValueOf(i interface { }) Value
2. 从实例到 Type:通过实例获取反射对象的 Type ,直接使用 reflect. TypeOf()函数。例如:
func TypeOf(i interface{}) Type
3. 从Type 到 Value:Type 里面只有类型信息,所以直接从 Type 接口变 里面是无法获得实例的 value的,但可以通过该 Type 构建 个新实例的 alue reflect 包提供了两种方法,示例如下:
// New 返回的是 Value ,该 Value type PtrTo (typ), 即Value Type 是指定的指针类型
func New(typ Type) Value
// Zero 返回的是 type 类型的零佳,注意返回的 Value 不能寻址, 值不可改变
func Zero(typ Type) Value
如果知道一个类型值的底层存放地址,则还有一个函数是可以依据 type 和该地址值恢复出value 的。例如
func NewAt(typ Type, p unsafe . Pointer) Value
4. 从Value Type:从反射对象 Valu Type 可以直接调用 Valu 的方法,因为 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
6. 从Value 的指针到值:从一 指针类型的 Value 获得值类型 Va ue 有两种方法,示例如下。
// 如果V类型是接口,则 Elem ()返回接口绑定的实例的 Value ,如过V类型是指针,则返回指针值的 Value ,否则引起 panic
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 值的修改涉及如下两个方法:
// 通过 Can Set 判断是否能修改
func (v Value ) CanSet( ) bool
// 通过 Set 进行修改
func (v Value ) Set(x Value )
5、反射三定律
(1)反射可以从接口值得到反射对象。
(2)反射可以从反射对象获得接口值。
(3)若要修改一个反射对象, 则其值必须可以修改。
6、反射的优点
(1)通用性:特别是一些类库和框架代码需要 种通用的处理模式,而不是 对每一种场景做硬编码处理,此时借助反射可以极大地简化设计。
(2)灵活性:反射提供了 种程序了解自己和改变自己的能力,这为一些测试工具的开发提供了有力的
支持。
7、反射的缺点
(1)反射是脆弱的:由于反射可以在程序运行时修改程序的状态,这种修改没有经过编译器的严格检查,不正确的修改很容导致程序的崩溃。
(2)反射是晦涩难懂的:语言的反射接口由于涉及语言的运行时,没有具体的类型系统的约束,接口的抽象级别高但实现细节复杂,导致使用反射的代码难以理解。
(3)反射有部分性能损失:反射提供动态修改程序状态的能力,必然不是直接的地址引用,而是要借助运行时构造个抽象层,这种间接访问会有性能的损失。
8、反射的最佳实践
(1)在库或框架内部使用反射时,而不是把反射接口暴露给调用者,复杂性留在内部,简单性放到接口。
(2)框架代码才考虑使用反射,一般的业务代码没有必要抽象到反射的层次,这种过度设计会带来复杂度的提升,使得代码难以维护。
(3)除非没有其他办法,否则不要使用反射技术。