反射能够让我们在程序的运行期间探知对象的类型信息和内存结构。比如我们用一个空接口来接收用户输入的内容,但是如果想知道用户输入内容的类型的话就只能在程序运行过程中动态的去判断,这个时候就要用到反射,反射能够在程序运行时动态的获取一个变量的类型信息和值信息。
在reflect
包中有两个重要的类型:Type
和Value
,这两个类型都具有很多定义好的方法,我们可以直接调用。
Typeof
在Go
语言中可以通过reflect.Typeof
获取任意值的类型对象,我们可以通过返回的类型对象来访问任意值的类型信息。
func main() {
a := 100
v := reflect.TypeOf(a)
fmt.Println(v) // int
}
在反射中类型分为两类,一种是Type
,另一种是Kind
。因为在Go
语言中我们可以使用type
关键字构造很多自定义类型,前者表示真实的、定义的类型,后者表示其基础的、底层的结构的类型。
func main() {
type X int
var a X
a = 100
v := reflect.TypeOf(a)
fmt.Println(v.Name(),v.Kind()) // X int
}
需要注意的是,在Go
语言中,数组、切片、Map
、指针等类型的变量,它们的.Name()
都是空
。
func main() {
var a = [3]int{
0,1,2}
v := reflect.TypeOf(a)
fmt.Println(v.Name()) // 输出为空
}
reflect
的传入对象应该区分基类型和指针类型,因为它们并不属于同一类型。使用方法Elem
可以返回指针、数组、切片、字典(值)或通道的基类型
。
func main() {
a := 100
v1 := reflect.TypeOf(a)
v2 := reflect.TypeOf(&a)
fmt.Println(v1,v2,v1==v2) // int *int false
fmt.Println(v1.Kind(),v2.Kind()) // int ptr
fmt.Println(v1,v2.Elem(),v1==v2.Elem()) // int int true
fmt.Println(reflect.TypeOf(map[string]int{
}).Elem(