反射是什么
- 静态类型语言的程序要编译成可执行文件才能执行,在编译阶段变量类型信息(元信息)被擦除,只剩地址和长度.要想访问元信息需要通过特殊的办法–反射.
- 动态类型的语言通过解释执行的,源码一直存在,所以能轻松的访问到元信息.
go 的反射机制
Go 语言提供了一种机制在运行时更新变量和检查他们的值,调用它们的方法,但是在编译时并不知道这些变量的具体类型,这称为反射机制. – Go 程序设计语言
类型擦除
源码
package main
import "fmt"
func main() {
var (
a = 1
b = 2
)
c := a + b
fmt.Println(c)
}
汇编
$ go tool compile -l -N -S e.go
"".main STEXT size=220 args=0x0 locals=0x88
...
0x002f 00047 (e.go:7) MOVQ $1, "".a+64(SP)
0x0038 00056 (e.go:8) MOVQ $2, "".b+56(SP)
...
结论
经过汇编后变量 a 和 b 只有地址和长度信息了,其它元信息被擦除 - 类型擦除.
实现
主要思想
:假设有变量 x 和 rx ,通过 rx = reflect.ValueOf(x) 将 x 的元信息放入 rx.这样源码被编译后,虽然 x 被类型擦除(只剩地址和长度),但是 rx 里面还存着一份元信息, rx 就是 x 的影子. 元信息从源码进入了运行时.
reflect 包
三个重要的类型
- Kind
- Type
- Value
它们之间的关系
类型(输入参数/接收器) | 函数/方法 | 类型(返回值) |
---|---|---|
type | TypeOf() | Type |
type | ValueOf() | Value |
Type | Kind() | Kind |
Value | Kind() | Kind |
Value | Type() | Type |
注: type 指 go 的类型,如int,slice,struct…等.
Kind 类型
种类 Kind
是对类型(type)的分类,比如定义了 type Ta struct{}
和 type Tb struct{b int}
,那么 Ta
和 Tb
都属于 Struct
这个种类,又比如所有的指针类型都属于 Ptr
这个种类.可见 Kind 分类粒度比 type 粗.这样每种 Kind 都有同样的元信息(所有的结构体有域的概念,所有数组有元素概念),可以用统一的方式处理(访问和设置),具体参考下文 Type 和 Value .
Kind 实现成 unit 类型,可以起到索引的效果,把它作用于 kindNames 数组就可以得到对应的种类名称.
type Kind uint
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)
var kindNames = []string{
Invalid: "invalid",
Bool: "bool",
Int: "int",
Int8: "int8",
Int16: "int16",
Int32: "int32",
Int64: "int64",
Uint: "uint",
Uint8: "uint8",
Uint16: "uint16",
Uint32: "uint32",
Uint64: "uint64",
Uintptr: "uintptr",
Float32: "float32",
Float64: "float64",
Complex64: "complex64",
Complex128: "complex128",
Array: "array",
Chan: "chan",
Func: "func",
Interface: "interface",
Map: "map",
Ptr: "ptr",
Slice: "slice",
String: "string",
Struct: "struct",
UnsafePointer: "unsafe.Pointer",
}
Type 类型
类型 Type
是对类型(type)的描述,是它的在运行时代表.实现为接口(interface)类型.
按 Kind 分类
- 通用的方法
- Name() string
- PkgPath() string
- Size() uintptr
- Name() string
- PkgPath() string
- Size() uintptr
- String() string
- Kind() Kind
- Implements(u Type) bool
- AssignableTo(u Type) bool
- ConvertibleTo(u Type) bool
- Comparable() bool
- Bits() intd
- Struct
- FieldAlign() int
- Field(i int) StructField
- FieldByIndex(index []int) StructField
- FieldByName(name string) (StructField, bool)
- FieldByNameFunc(match func(string) bool) (StructField, bool)
- NumField() inc
- Method(int) Method
- MethodByName(string) (Method, bool)
- NumMethod() int
- Func
- In(i int) Type
- IsVariadic() bool
- NumIn() int
- NumOut() int
- Out(i int) Type
- Array / Chan / Map / Ptr / Slice
- Elem() Type
- Chan
- ChanDir() ChanDir
- Map
- Key() Type
- Array
- Len() int
type Type interface {
Align() int
FieldAlign() int
Method(int) Method
MethodByName(string) (Method, bool)
NumMethod() int
Name() string
PkgPath() string
Size() uintptr
String() string
Kind() Kind
Implements(u Type) bool
AssignableTo(u Type) bool
ConvertibleTo(u Type) bool
Comparable() bool
Bits() int
ChanDir() ChanDir
IsVariadic() bool
Elem() Type
Field(i int) StructField
FieldByIndex(index []int) StructField
FieldByName(name string) (StructField, bool)
FieldByNameFunc(match func(string) bool) (StructField, bool)
In(i int) Type
Key() Type
Len() int
NumField() int
NumIn() int
NumOut() int
Out(i int) Type
}
Value 类型
值 Value
是对对象的描述,包含对象的地址和类型信息.实现为结构(struct)类型.它的方法有些是通用的,有些是特定 Kind 才有的,主要分为
- 断言相关方法
- 查询相关方法
- 设置相关方法
type Value struct {
typ *rtype
ptr unsafe.Pointer
flag
}
func (v Value) Addr() Value
func (v Value) Bool() bool
func (v Value) Bytes() []byte
func (v Value) Call(in []Value) []Value
func (v Value) CallSlice(in []Value) []Value
func (v Value) CanAddr() bool
func (v Value) CanInterface() bool
func (v Value) CanSet() bool
func (v Value) Cap() int
func (v Value) Close()
func (v Value) Complex() complex128
func (v Value) Convert(t Type) Value
func (v Value) Elem() Value
func (v Value) Field(i int) Value
func (v Value) FieldByIndex(index []int) Value
func (v Value) FieldByName(name string) Value
func (v Value) FieldByNameFunc(match func(string) bool) Value
func (v Value) Float() float64
func (v Value) Index(i int) Value
func (v Value) Int() int64
func (v Value) Interface() (i interface{})
func (v Value) InterfaceData() [2]uintptr
func (v Value) IsNil() bool
func (v Value) IsValid() bool
func (v Value) Kind() Kind
func (v Value) Len() int
func (v Value) MapIndex(key Value) Value
func (v Value) MapKeys() []Value
func (v Value) MapRange() *MapIter
func (v Value) Method(i int) Value
func (v Value) MethodByName(name string) Value
func (v Value) NumField() int
func (v Value) NumMethod() int
func (v Value) OverflowComplex(x complex128) bool
func (v Value) OverflowFloat(x float64) bool
func (v Value) OverflowInt(x int64) bool
func (v Value) OverflowUint(x uint64) bool
func (v Value) Pointer() uintptr
func (v Value) Recv() (x Value, ok bool)
func (v Value) Send(x Value)
func (v Value) Set(x Value)
func (v Value) SetBool(x bool)
func (v Value) SetBytes(x []byte)
func (v Value) SetCap(n int)
func (v Value) SetComplex(x complex128)
func (v Value) SetFloat(x float64)
func (v Value) SetInt(x int64)
func (v Value) SetLen(n int)
func (v Value) SetMapIndex(key, val Value)
func (v Value) SetPointer(x unsafe.Pointer)
func (v Value) SetString(x string)
func (v Value) SetUint(x uint64)
func (v Value) Slice(i, j int) Value
func (v Value) Slice3(i, j, k int) Value
func (v Value) String() string
func (v Value) TryRecv() (x Value, ok bool)
func (v Value) TrySend(x Value) bool
func (v Value) Type() Type
func (v Value) Uint() uint64
func (v Value) UnsafeAddr() uintptr
例子
标准库是最好的例子,这里从标准库里截取几段代码
片段一
//encoding/json/decode.go
//...
if v.Kind() == reflect.Interface && !v.IsNil() {
e := v.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
haveAddr = false
v = e
continue
}
}
if v.Kind() != reflect.Ptr {
break
}
if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() {
break
}
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
if v.Type().NumMethod() > 0 && v.CanInterface() {
if u, ok := v.Interface().(Unmarshaler); ok {
return u, nil, reflect.Value{}
}
if !decodingNull {
if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
return nil, u, reflect.Value{}
}
}
}
//...
片段二
//encoding/json/encode.go
func isEmptyValue(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
}
return false
}
推荐
https://mp.weixin.qq.com/s/9P_ah0dqSbsNGU6dv7fJzw