写一段最简单的代码看看golang的反射机制是怎么做的。
import (
"fmt"
"reflect"
)
func main() {
var a int
typeOfA := reflect.TypeOf(a)
fmt.Println(typeOfA.String())
fmt.Println(typeOfA.Kind())
}
看看这个TypeOf是怎么实现的
func TypeOf(i interface{}) Type {
eface := *(*emptyInterface)(unsafe.Pointer(&i))
return toType(eface.typ)
}
这里的Type是一个Interface{},看不出是什么。
这个unsafe.Pointer是个什么?
type Pointer *ArbitraryType
type ArbitraryType int
原来是个指针,存储内存地址。只是有点好奇,这个int在32系统下是不是就4字节,而在64系统下就是8个字节?有待求证啊。
再看看那个emptyInterface,名字取得真怪,空接口,这是什么鬼?
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ *rtype
word unsafe.Pointer
}
原来是个结构体。注释说它表示interface{}的头部。它有两个字段。后面的那个好像没什么意思,就一指针,有更多内容的是第一个字段,进去看看。
// rtype is the common implementation of most values.
// It is embedded in other struct types.
//
// rtype must be kept in sync with ../runtime/type.go:/^type._type.
type rtype struct {
size uintptr
ptrdata uintptr // number of bytes in the type that can contain pointers
hash uint32 // hash of type; avoids computation in hash tables
tflag tflag // extra type information flags
align uint8 // alignment of variable with this type
fieldAlign uint8 // alignment of struct field with this type
kind uint8 // enumeration for C
alg *typeAlg // algorithm table
gcdata *byte // garbage collection data
str nameOff // string form
ptrToThis typeOff // type for pointer to this type, may be zero
}
果然是很有料。好像是定义了类型的大多数属性,存储大小,对齐什么的,暂时也搞不明白。注释说它用来嵌入其他结构体类型,看看它怎么用的。
type arrayType struct {
rtype
elem *rtype // array element type
slice *rtype // slice type
len uintptr
}
// chanType represents a channel type.
type chanType struct {
rtype
elem *rtype // channel element type
dir uintptr // channel direction (ChanDir)
}
type funcType struct {
rtype
inCount uint16
outCount uint16 // top bit is set if last input parameter is ...
}
还有很多就不列举了,看来rtype真的是嵌入其他结构体里。暂时不扩展那么开,调试一下看看运行流程是怎么样的。
结果我运行后,就发现这么一个现象:
调试运行到这里的时候,就发现eface值就突然多了很多值,也不知道是在哪里赋值的。好像是突然冒出来的。这里也没有赋值的地方啊,只是把它的地址类型转换了一下而已。这怎么解释这种现象?
我想应该是在这里
func TypeOf(i interface{}) Type {
这个函数的参数是一个interface{}。
当把一个int类型的变量传入这个函数时,会构建一个interface{}类型的内存区域。因为golang的语法保证任何类型都可以转换为interface{} 而不会引发错误,所以可以把interface{}看作是一种特殊的struct。当把其他类型转换为interface{}的时候,会开辟一块内存空间存储一些跟原来类型相关的数据,就像上面那个图里显示的那些数据一样。
所以反射的本质是什么呢?
反射的本质就是把其他类型转换为interface{}的时候,会自动为其他类型开辟一块内存区域,存储跟那个类型有关的数据。
后面调用各种函数都是对这些数据的一些读取转换操作而已。
(全文完)