深入浅出go反射

写在前面

Go的反射机制带来很多动态特性,一定程度上弥补了Go缺少自定义范型而导致的不便利。

Go反射机制设计的目标之一是任何操作(非反射)都可以通过反射机制来完成

变量是由两部分组成:变量的类型和变量的值。

类型和值

reflect.Typereflect.Value是反射的两大基本要素,他们的关系如下:

  • 任意类型都可以转换成TypeValue
  • Value可以转换成Type
  • Value可以转换成Interface

image-20210226092816988

Type

类型系统

Type描述的是变量的类型,关于类型请参考下面这个文章:

Go类型系统概述

Go语言的类型系统非常重要,如果不熟知这些概念,则很难精通Go编程。

Type是什么?

reflect.Type实际上是一个接口,它提供很多api(方法)让你获取变量的各种信息。比如对于数组提供了LenElem两个方法分别获取数组的长度和元素。

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
}

不同类型可以使用的方法如下:

image-20210226092843752

每种类型可以使用的方法都是不一样的,错误的使用会引发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.
   
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值