go 反射机制

反射是什么

  • 静态类型语言的程序要编译成可执行文件才能执行,在编译阶段变量类型信息(元信息)被擦除,只剩地址和长度.要想访问元信息需要通过特殊的办法–反射.
  • 动态类型的语言通过解释执行的,源码一直存在,所以能轻松的访问到元信息.

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

它们之间的关系

类型(输入参数/接收器)函数/方法类型(返回值)
typeTypeOf()Type
typeValueOf()Value
TypeKind()Kind
ValueKind()Kind
ValueType()Type

注: type 指 go 的类型,如int,slice,struct…等.

Kind 类型
种类 Kind 是对类型(type)的分类,比如定义了 type Ta struct{}type Tb struct{b int},那么 TaTb 都属于 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

参考

Go程序设计语言

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值