写在前面
Go的反射机制带来很多动态特性,一定程度上弥补了Go缺少自定义范型而导致的不便利。
Go反射机制设计的目标之一是任何操作(非反射)都可以通过反射机制来完成。
变量是由两部分组成:变量的类型和变量的值。
类型和值
reflect.Type
和reflect.Value
是反射的两大基本要素,他们的关系如下:
- 任意类型都可以转换成
Type
和Value
Value
可以转换成Type
Value
可以转换成Interface
Type
类型系统
Type
描述的是变量的类型,关于类型请参考下面这个文章:
Go语言的类型系统非常重要,如果不熟知这些概念,则很难精通Go编程。
Type是什么?
reflect.Type
实际上是一个接口,它提供很多api
(方法)让你获取变量的各种信息。比如对于数组提供了Len
和Elem
两个方法分别获取数组的长度和元素。
type Type interface {
// Elem returns a type's element type.
// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
Elem() Type
// Len returns an array type's length.
// It panics if the type's Kind is not Array.
Len() int
}
不同类型可以使用的方法如下:
每种类型可以使用的方法都是不一样的,错误的使用会引发panic
。
思考:为什么
array
支持Len
方法,而slice
不支持?
Type有哪些实现?
使用reflect.TypeOf
可以获取变量的Type
func TypeOf(i interface{
}) Type {
eface := *(*emptyInterface)(unsafe.Pointer(&i)) // 强制转换成*emptyInterface类型
return toType(eface.typ)
}
我需要知道TypeOf反射的是变量的类型,而不是变量的值(这点非常的重要)。
unsafe.Pointer(&i)
,先将i
的地址转换成Pointer
类型(*emptyInterface)(unsafe.Pointer(&i))
,强制转换成*emptyInterface
类型*(*emptyInterface)(unsafe.Pointer(&i))
,解引用,所以eface
就是emptyInterface
通过unsafe
的骚操作,我们可以将任意类型转换成emptyInterface
类型。因为emptyInterface
是不可导出的,所以使用toType
方法将*rtype
包装成可导出的reflect.Type
。
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ *rtype
word unsafe.Pointer
}
// toType converts from a *rtype to a Type that can be returned
// to the client of package reflect. In gc, the only concern is that
// a nil *rtype must be replaced by a nil Type, but in gccgo this
// function takes care of ensuring that multiple *rtype for the same
// type are coalesced into a single Type.
func toType(t *rtype) Type {
if t == nil {
return nil
}
return t
}
所以,rtype
就是reflect.Type
的一种实现。
rtype结构解析
下面重点看下rtype
结构体:
type rtype struct {
size uintptr // 类型占用空间大小
ptrdata uintptr // size of memory prefix holding all pointers
hash uint32 // 唯一hash,表示唯一的类型
tflag tflag // 标志位
align uint8 // 内存对其
fieldAlign uint8
kind uint8 //
/**
func (t *rtype) Comparable() bool {
return t.equal != nil
}
*/
equal func(unsafe.Pointer, unsafe.Pointer) bool // 比较函数,是否可以比较
// gcdata stores the GC type data for the garbage collector.
// If the KindGCProg bit is set in kind, gcdata is a GC program.