面壁者“变量”,我是你的破壁人
《Go 语言圣经》中是这样定义反射的:
Go 语言提供了一种机制在运行时更新变量和检查它们的值、调用它们的方法,但是在编译时并不知道这些变量的具体类型,这称为反射机制。
what's that mean? 不着急,下面通过一个函数来理解:
我们定义了一个judgeType函数,形参是一个空接口类型,这样它就可以接受任意类型的参数,函数目的是判断传入任意参数的类型
尽管可以通过类型断言配合switch语句来简单判断变量v的类型,但这样的缺点是我们可能要写无数个case语句块(golang的类型是无限的,比如数组不同的长度都是不同的类型),才能判断出所有的类型
所以这样是不可取的,有一个办法可以扒下interface{}变量的底裤,得知它的前世今生,那就是利用反射(reflection)
内置反射reflect包当我们将一个某具体类型的变量赋予给interface{}变量时,golang会记录下原变量的类型(type)和值(value),这时可以通过reflect包的一些函数来获取到它们
reflect包实现了golang中运行时的反射机制。reflect包可以帮助我们得知interface{}变量底层具体的类型与值(underlying concrete type and the value)
reflect包定义了两个核心的类型,一个是接口类型reflect.Type:
可以通过reflect.TypeOf函数得到空接口底层的Type:
另一个是结构体类型reflect.Value:
可以通过reflect.ValueOf函数得到空接口底层的Value:
简单地得知interface{}底层的类型(有点像fmt的%T标记):
也可以通过Kind方法得到具体的类型:
reflect.Type.Kind方法返回一个reflect包的类型Kind,它的定义如下:
通过NumField方法,得知结构体的字段个数,包括私有的字段:
得到结构体字段的标签信息(json包就应用了tag):
得到数组的长度:
通过NumMethod方法,得知结构体的方法个数,不包括私有的方法,通过Method方法得到具体的函数:
只得到了Hello方法,因为eat方法是私有的(unexported),而Hi方法是Person的指针方法
得到函数的入参/出参个数:
IsVariadic方法得知函数入参是否包含可变参数:
Elem方法可以得知数组、通道、映射、指针、切片的元素的类型:
得到map的key和value的类型:
也可以根据名称获取对应字段(FieldByName)或方法(MethodByName):
通过ChanDir方法可以得知通道的方向:
OK,到这我们通过reflect.Type便基本得知了运行时interface{}的底层信息
明天继续讲如何修改底层的数据、调用底层的方法,bye~